1
0
Fork 0

wip(shared): Changes to layouts

This will break the org build, but we need to rip out sanity anyway so
I don't think it's worth obsessing over it now.

I've essentially changes the default layout and added a new navigation
component.
This commit is contained in:
joostdecock 2023-07-15 16:55:22 +02:00
parent 8b79de2bd6
commit 5a9f2f8d40
26 changed files with 318 additions and 172 deletions

View file

@ -16,6 +16,7 @@ import {
MeasieIcon,
PageIcon,
PlusIcon,
RssIcon,
} from 'shared/components/icons.mjs'
import { HeaderWrapper } from 'shared/components/wrappers/header.mjs'
import { ModalThemePicker, ns as themeNs } from 'shared/components/modal/theme-picker.mjs'
@ -40,20 +41,20 @@ const NavIcons = ({ setModal, setSearch }) => {
<DesignIcon className={iconSize} />
</NavButton>
<NavButton
href="/patterns"
label={t('header:patterns')}
href="/docs"
label={t('header:docs')}
color={colors[2]}
extraClasses="hidden lg:flex"
>
<PageIcon className={iconSize} />
<DocsIcon className={iconSize} />
</NavButton>
<NavButton
href="/sets"
label={t('header:sets')}
href="/blog"
label={t('header:blog')}
color={colors[3]}
extraClasses="hidden lg:flex"
>
<MeasieIcon className={iconSize} />
<RssIcon className={iconSize} />
</NavButton>
<NavButton
href="/showcase"
@ -63,39 +64,44 @@ const NavIcons = ({ setModal, setSearch }) => {
>
<ShowcaseIcon className={iconSize} />
</NavButton>
<NavSpacer />
<NavButton
href="/docs"
label={t('header:docs')}
href="/patterns"
label={t('header:patterns')}
color={colors[5]}
extraClasses="hidden lg:flex"
>
<DocsIcon className={iconSize} />
<PageIcon className={iconSize} />
</NavButton>
<NavButton
href="/sets"
label={t('header:sets')}
color={colors[6]}
extraClasses="hidden lg:flex"
>
<MeasieIcon className={iconSize} />
</NavButton>
<NavButton href="/account" label={t('header:account')} color={colors[7]}>
<UserIcon className={iconSize} />
</NavButton>
<NavSpacer />
<NavButton
onClick={() => setModal(<ModalThemePicker />)}
label={t('header:theme')}
color={colors[6]}
color={colors[8]}
>
<ThemeIcon className={iconSize} />
</NavButton>
<NavButton
onClick={() => setModal(<ModalLocalePicker />)}
label={t('header:language')}
color={colors[7]}
color={colors[9]}
>
<I18nIcon className={iconSize} />
</NavButton>
<NavButton onClick={() => setSearch(true)} label={t('header:search')} color={colors[8]}>
<NavButton onClick={() => setSearch(true)} label={t('header:search')} color={colors[10]}>
<SearchIcon className={iconSize} />
</NavButton>
<NavSpacer />
<NavButton href="/account" label={t('header:account')} color={colors[9]}>
<UserIcon className={iconSize} />
</NavButton>
<NavButton href="/new" label={t('header:new')} color={colors[10]}>
<PlusIcon className={iconSize} />
</NavButton>
</>
)
}

View file

@ -1,10 +1,3 @@
import { AsideNavigation } from 'shared/components/navigation/aside.mjs'
export const ns = []
export const BareLayout = (props) => (
<>
<AsideNavigation mobileOnly />
{props.children}
</>
)
export const BareLayout = (props) => props.children

View file

@ -1,26 +1,43 @@
// Hooks
import { useContext } from 'react'
// Components
import { AsideNavigation, ns as navNs } from 'shared/components/navigation/aside.mjs'
import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs'
import { useNavigation } from 'site/hooks/use-navigation.mjs'
// Context
import { NavigationContext } from 'shared/context/navigation-context.mjs'
// Components
//import { AsideNavigation, ns as navNs } from 'shared/components/navigation/aside.mjs'
//import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs'
//import { NavigationContext } from 'shared/context/navigation-context.mjs'
export const ns = navNs
import { BaseLayout, BaseLayoutLeft, BaseLayoutWide } from 'shared/components/base-layout.mjs'
import { NavLinks, Breadcrumbs, MainSections } from 'shared/components/navigation/sitenav.mjs'
export const DefaultLayout = ({ children = [], pageTitle = false }) => {
const { crumbs } = useContext(NavigationContext)
export const ns = [] //navNs
export const DefaultLayout = ({ children = [], slug, pageTitle = false }) => {
const { siteNav } = useNavigation({ ignoreControl: true })
return (
<div className="grid grid-cols-4 mx-auto justify-center place-items-stretch">
<AsideNavigation />
<section className="col-span-4 lg:col-span-3 py-8 lg:py-24 px-4 lg:pl-8 bg-base-50">
<BaseLayout>
<BaseLayoutLeft>
{slug ? (
<>
<MainSections {...{ siteNav, slug }} />
<NavLinks {...{ siteNav, slug }} />
</>
) : (
<p>Slug not passed to layout</p>
)}
</BaseLayoutLeft>
<BaseLayoutWide>
{pageTitle && (
<div className="xl:pl-4">
<Breadcrumbs crumbs={crumbs} title={pageTitle} />
{slug && <Breadcrumbs {...{ siteNav, slug }} />}
<h1 className="break-words">{pageTitle}</h1>
</div>
)}
<div className="xl:pl-4">{children}</div>
</section>
</div>
</BaseLayoutWide>
</BaseLayout>
)
}

View file

@ -0,0 +1,69 @@
// Hooks
import { useNavigation } from 'site/hooks/use-navigation.mjs'
// Components
import Head from 'next/head'
import {
BaseLayout,
BaseLayoutLeft,
BaseLayoutProse,
BaseLayoutRight,
} from 'shared/components/base-layout.mjs'
import { NavLinks, Breadcrumbs, MainSections } from 'shared/components/navigation/sitenav.mjs'
import { Toc } from 'shared/components/mdx/toc.mjs'
import { MdxMetaData } from 'shared/components/mdx/meta.mjs'
import { PrevNext } from 'shared/components/prev-next.mjs'
export const ns = [] //navNs
export const DocsLayout = ({ children = [], slug, frontmatter }) => {
const { siteNav } = useNavigation({ ignoreControl: true })
return (
<>
<Head>
<meta property="og:title" content={frontmatter.title} key="title" />
<meta property="og:type" content="article" key="type" />
<meta property="og:description" content={``} 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/org/${slug}}`}
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.org/${slug}`} key="url" />
<meta property="og:locale" content="en" key="locale" />
<meta property="og:site_name" content="freesewing.org" key="site" />
<title>{frontmatter.title} - FreeSewing.org</title>
</Head>
<BaseLayout>
<BaseLayoutLeft>
<MainSections {...{ siteNav, slug }} />
<NavLinks {...{ siteNav, slug }} />
</BaseLayoutLeft>
<BaseLayoutProse>
<div className="w-full">
<Breadcrumbs {...{ siteNav, slug }} />
<h1 className="break-words searchme">{frontmatter.title}</h1>
<div className="block xl:hidden">
<Toc toc={frontmatter.toc} wrap />
</div>
</div>
{children}
<PrevNext slug={slug} noPrev={slug === 'docs'} />
</BaseLayoutProse>
<BaseLayoutRight>
<MdxMetaData frontmatter={frontmatter} slug={slug} locale="en" />
<div className="hidden xl:block">
<Toc toc={frontmatter.toc} wrap />
</div>
</BaseLayoutRight>
</BaseLayout>
</>
)
}

View file

@ -1,4 +0,0 @@
export const ns = []
// This layout adds nothing
export const NoLayout = ({ children = [] }) => children

View file

@ -17,10 +17,12 @@ export const SanityPageWrapper = ({
author = {},
page = {},
namespaces = ['common'],
slug,
}) => {
const { t } = useTranslation(namespaces)
console.log({ slug })
return (
<PageWrapper title={post.title} {...page}>
<PageWrapper title={post.title} {...page} slug={slug}>
<Head>
<meta property="og:type" content="article" key="type" />
<meta property="og:description" content={post.intro || post.title} key="description" />

View file

@ -14,8 +14,17 @@ import { useRouter } from 'next/router'
* - home page => no navvigation shown
* - /contact => Added below
*
* Note: Set 'h' to truthy to not show a top-level entry as a section
* Note: Set 'c' to set the control level to hide things from users
* 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 ns = ['account', 'sections', 'design', 'tags', 'designs']
@ -26,55 +35,59 @@ const sitePages = (t = false, control = 99) => {
const pages = {
// Top-level pages that are the sections menu
designs: {
t: t('sections:designs'),
m: 1,
s: 'designs',
o: 10,
t: t('sections:designs'),
n: 1,
tags: {
t: t('design:tags'),
_: 1,
s: 'designs/tags',
h: 1,
t: t('design:tags'),
o: 'aaa',
},
},
patterns: {
t: t('sections:patterns'),
m: 1,
s: 'patterns',
o: 14,
t: t('sections:patterns'),
},
sets: {
t: t('sections:sets'),
m: 1,
s: 'sets',
o: 16,
t: t('sections:sets'),
},
community: {
t: t('sections:community'),
m: 1,
s: 'community',
o: 40,
t: t('sections:community'),
},
account: {
t: t('sections:account'),
m: 1,
s: 'account',
o: 99,
t: t('sections:account'),
n: 1,
},
// Top-level pages that are not in the sections menu
apikeys: {
t: t('apikeys'),
_: 1,
s: 'apikeys',
h: 1,
t: t('apikeys'),
},
curate: {
t: t('curate'),
s: 'curate',
h: 1,
t: t('curate'),
sets: {
t: t('curateSets'),
s: 'curate/sets',
},
},
new: {
t: t('new'),
m: 1,
s: 'new',
h: 1,
t: t('new'),
pattern: {
t: t('patternNew'),
s: 'new/pattern',
@ -87,56 +100,54 @@ const sitePages = (t = false, control = 99) => {
},
},
profile: {
t: t('yourProfile'),
s: 'profile',
h: 1,
t: t('yourProfile'),
},
translation: {
t: t('translation'),
s: 'translation',
h: 1,
t: t('translation'),
join: {
t: t('translation:joinATranslationTeam'),
s: 'translation',
h: 1,
},
'suggest-language': {
t: t('translation:suggestLanguage'),
s: 'translation',
h: 1,
},
},
sitemap: {
t: t('sitemap'),
s: 'sitemap',
h: 1,
t: t('sitemap'),
},
// Not translated, this is a developer page
typography: {
t: 'Typography',
s: 'typography',
h: 1,
t: 'Typography',
},
}
for (const section in conf.account.fields) {
for (const [field, controlScore] of Object.entries(conf.account.fields[section])) {
if (Number(control) >= controlScore)
pages.account[field] = {
t: t(`account:${field}`),
s: `account/${field}`,
t: t(`account:${field}`),
}
}
}
if (Number(control) >= conf.account.fields.developer.apikeys)
pages.new.apikey = {
t: t('newApikey'),
s: 'new/apikey',
t: t('newApikey'),
o: 30,
}
pages.account.reload = {
t: t(`account:reload`),
s: `account/reload`,
t: t(`account:reload`),
}
for (const design in designs) {
// pages.designs[design] = {
@ -144,21 +155,22 @@ const sitePages = (t = false, control = 99) => {
// s: `designs/${design}`,
// }
pages.new.pattern[design] = {
t: t(`account:generateANewThing`, { thing: t(`designs:${design}.t`) }),
s: `new/${design}`,
t: t(`account:generateANewThing`, { thing: t(`designs:${design}.t`) }),
}
}
for (const tag of tags) {
pages.designs.tags[tag] = {
t: t(`tags:${tag}`),
s: `designs/tags/${tag}`,
t: t(`tags:${tag}`),
}
}
return pages
}
export const useNavigation = ({ ignoreControl = false }, extra = []) => {
export const useNavigation = (param = {}, extra = []) => {
const { ignoreControl = false } = param
// Passing in the locale is not very DRY so let's just grab it from the router
const { locale } = useRouter()
// We need translation
@ -174,8 +186,23 @@ export const useNavigation = ({ ignoreControl = false }, extra = []) => {
objUpdate(siteNav, _path, _data)
}
// Set order on docs key (from from prebuild siteNav)
siteNav.docs.o = 30
// Apply some tweaks
siteNav.blog.m = 1
siteNav.blog.n = 1
siteNav.showcase.m = 1
siteNav.showcase.n = 1
siteNav.docs.m = 1
// Set order on main sections
siteNav.designs.o = 10
siteNav.docs.o = 20
siteNav.blog.o = 30
siteNav.showcase.o = 40
siteNav.community.o = 50
siteNav.patterns.o = 60
siteNav.sets.o = 70
siteNav.account.o = 80
siteNav.new.o = 90
return {
siteNav, // Site navigation

View file

@ -11,6 +11,7 @@ import { Spinner } from 'shared/components/spinner.mjs'
import { components } from 'shared/components/mdx/index.mjs'
import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
import { Toc } from 'shared/components/mdx/toc.mjs'
import { DocsLayout } from 'site/components/layouts/docs.mjs'
/*
* PLEASE READ THIS BEFORE YOU TRY TO REFACTOR THIS PAGE
@ -61,7 +62,11 @@ const HeadInfo = ({ frontmatter, locale, slug }) => (
)
export const Page = ({ page, frontmatter, slug, locale, MDX }) => (
<PageWrapper {...page} title={frontmatter.title}>
<PageWrapper
{...page}
title={frontmatter.title}
layout={(props) => <DocsLayout {...props} {...{ slug, frontmatter }} />}
>
<HeadInfo {...{ frontmatter, locale, slug }} />
<div className="flex flex-row-reverse flex-wrap xl:flex-nowrap justify-end">
{frontmatter.toc && frontmatter.toc.length > 0 && (

View file

@ -4,7 +4,6 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useTranslation } from 'next-i18next'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { BareLayout as Layout } from 'site/components/layouts/bare.mjs'
import { TranslationStatus } from 'site/components/crowdin/status.mjs'
import { Translators } from 'site/components/crowdin/translators.mjs'
import { Popout } from 'shared/components/popout.mjs'
@ -20,26 +19,29 @@ const TranslationPage = ({ page }) => {
const title = t('translation:translation')
return (
<PageWrapper {...page} layout={Layout}>
<div className="max-w-4xl mx-auto p-4 mt-4">
<Breadcrumbs crumbs={[{ s: 'translation', t: title }]} title={title} />
<h1>{title}</h1>
<PageWrapper {...page} title={title}>
<div className="max-w-2xl">
<p>{t('translation:proudlyMultilingual')}</p>
<div className="max-w-2xl">
<Popout tip>
<h5>{t('translation:getInvolved')}</h5>
<p>{t('translation:teamEffort')}</p>
<p>
<Link href="/translation/join" className="btn btn-accent mr-2">
{t('translation:joinTheTeam')}
</Link>
</p>
<p>
<a
href="https://freesewing.dev/guides/translation"
className="btn btn-accent btn-outline"
>
{t('translation:seeTranslationGuide')}
</a>
</p>
</Popout>
</div>
<h2 id="status">Translation Status</h2>
<TranslationStatus />
@ -91,6 +93,7 @@ const TranslationPage = ({ page }) => {
<b>{t('locales:uk')}</b>
</li>
</ul>
<div className="max-w-3xl">
<Popout tip>
<h5>{t('translation:addLanguage1')}</h5>
<p>
@ -98,17 +101,22 @@ const TranslationPage = ({ page }) => {
<br />
{t('translation:addLanguage3')}
</p>
<p>
<Link href="/translation/suggest-language" className="btn btn-accent mr-2">
{t('translation:suggestLanguage')}
</Link>
</p>
<p>
<a
href="https://freesewing.dev/guides/translation"
className="btn btn-accent btn-outline"
>
{t('translation:seeTranslationGuide')}
</a>
</p>
</Popout>
</div>
</div>
</PageWrapper>
)
}

View file

@ -5,8 +5,6 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useTranslation } from 'next-i18next'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { BareLayout as Layout } from 'site/components/layouts/bare.mjs'
import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs'
// Translation namespaces used on this page
const namespaces = [...new Set(pageNs), 'translation', 'locales']
@ -31,17 +29,7 @@ const TranslationJoinPage = ({ page }) => {
const title = t('translation:joinATranslationTeam')
return (
<PageWrapper {...page} layout={Layout}>
<div className="max-w-4xl mx-auto p-4 mt-4">
<Breadcrumbs
crumbs={[
{ s: 'translation', t: t('translation:translation') },
{ s: 'translation/join', t: title },
]}
title={title}
/>
<h1>{title}</h1>
<PageWrapper {...page} title={title}>
<p>
{t('translation:joinIntro')}
<br />
@ -50,7 +38,6 @@ const TranslationJoinPage = ({ page }) => {
<DynamicAuthWrapper>
<DynamicForm />
</DynamicAuthWrapper>
</div>
</PageWrapper>
)
}

View file

@ -5,8 +5,6 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useTranslation } from 'next-i18next'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { BareLayout as Layout } from 'site/components/layouts/bare.mjs'
import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs'
// Translation namespaces used on this page
const namespaces = [...new Set(pageNs), 'translation', 'locales']
@ -32,17 +30,8 @@ const SuggestLanguagePage = ({ page }) => {
const title = t('translation:suggestLanguage')
return (
<PageWrapper {...page} layout={Layout}>
<div className="max-w-4xl mx-auto p-4 mt-4">
<Breadcrumbs
crumbs={[
{ s: 'translation', t: t('translation:translation') },
{ s: 'translation/join', t: title },
]}
title={title}
/>
<h1>{title}</h1>
<PageWrapper {...page} title={title}>
<div className="max-w-2xl">
<p>
{t('translation:suggestIntro')}
<br />

View file

@ -32,7 +32,7 @@ const DynamicBio = dynamic(
const WelcomeBioPage = ({ page }) => (
<PageWrapper {...page} layout={BareLayout} footer={false}>
<DynamicAuthWrapper>
<div className="m-auto max-w-lg text-center lg:mt-24 p-8">
<div className="m-auto max-w-lg text-center lg:mt-4 p-8">
<DynamicBio title welcome />
</div>
</DynamicAuthWrapper>

View file

@ -32,7 +32,7 @@ const DynamicCompare = dynamic(
const WelcomeComparePage = ({ page }) => (
<PageWrapper {...page} layout={BareLayout} footer={false}>
<DynamicAuthWrapper>
<div className="m-auto max-w-lg text-center lg:mt-24 p-8">
<div className="m-auto max-w-lg text-center lg:mt-4 p-8">
<DynamicCompare title welcome />
</div>
</DynamicAuthWrapper>

View file

@ -37,7 +37,7 @@ const WelcomeImgPage = ({ page }) => {
return (
<PageWrapper {...page} title={t('imgTitle')} layout={BareLayout} footer={false}>
<DynamicAuthWrapper>
<div className="m-auto max-w-lg text-center lg:mt-24 p-8">
<div className="m-auto max-w-lg text-center lg:mt-4 p-8">
<DynamicImg title welcome />
</div>
</DynamicAuthWrapper>

View file

@ -32,7 +32,7 @@ const DynamicControl = dynamic(
const WelcomePage = ({ page }) => (
<PageWrapper {...page} layout={BareLayout} footer={false}>
<DynamicAuthWrapper>
<div className="m-auto max-w-lg text-center lg:mt-24 p-8">
<div className="m-auto max-w-lg text-center lg:mt-4 p-8">
<DynamicControl title welcome />
</div>
</DynamicAuthWrapper>

View file

@ -38,7 +38,7 @@ const WelcomeNewsletterPage = ({ page }) => {
return (
<PageWrapper {...page} title={t('title')} layout={BareLayout} footer={false}>
<DynamicAuthWrapper>
<div className="m-auto max-w-lg text-center lg:mt-24 p-8">
<div className="m-auto max-w-lg text-center lg:mt-4 p-8">
<DynamicNewsletter title welcome />
</div>
</DynamicAuthWrapper>

View file

@ -32,7 +32,7 @@ const DynamicImperial = dynamic(
const WelcomeUnitsPage = ({ page }) => (
<PageWrapper {...page} layout={BareLayout} footer={false}>
<DynamicAuthWrapper>
<div className="m-auto max-w-lg text-center lg:mt-24 p-8">
<div className="m-auto max-w-lg text-center lg:mt-4 p-8">
<DynamicImperial title welcome />
</div>
</DynamicAuthWrapper>

View file

@ -37,7 +37,7 @@ const WelcomeUsernamePage = ({ page }) => {
return (
<PageWrapper {...page} title={t('title')} layout={BareLayout} footer={false}>
<DynamicAuthWrapper>
<div className="m-auto max-w-lg text-center lg:mt-24 p-8">
<div className="m-auto max-w-lg text-center lg:mt-4 p-8">
<DynamicUsername title welcome />
</div>
</DynamicAuthWrapper>

View file

@ -0,0 +1,36 @@
/*
* The default full-page FreeSewing layout
*/
export const BaseLayout = ({ children = [] }) => (
<div className="flex flex-row items-start mt-8 w-full justify-between 2xl:px-36 xl:px-12 px-4">
{children}
</div>
)
/*
* The left column of the default layout
*/
export const BaseLayoutLeft = ({ children = [] }) => (
<div className="max-w-96 w-1/4 mt-8 hidden lg:block shrink-0">{children}</div>
)
/*
* The right column of the default layout
*/
export const BaseLayoutRight = ({ children = [] }) => (
<div className="max-w-96 w-1/4 mt-8 hidden xl:block">{children}</div>
)
/*
* The main column for prose (text like docs and so on)
*/
export const BaseLayoutProse = ({ children = [] }) => (
<div className="grow w-full m-auto max-w-prose mt-0 mb-8">{children}</div>
)
/*
* The central column for wide content (no max-width)
*/
export const BaseLayoutWide = ({ children = [] }) => (
<div className="grow w-full m-auto mt-0 mb-8 grow">{children}</div>
)

View file

@ -9,11 +9,13 @@ import { Pattern, PatternXray } from '@freesewing/react-components'
// Get code from children
export const asText = (reactEl) => {
if (reactEl) {
if (typeof reactEl.props.children === 'string') return reactEl.props.children
if (Array.isArray(reactEl.props.children)) {
return reactEl.props.children.map((el) => (typeof el === 'string' ? el : asText(el))).join('')
}
if (typeof reactEl.props.children === 'object') return asText(reactEl.props.children)
}
return ''
}

View file

@ -17,6 +17,7 @@ import {
FreeSewingIcon,
HeartIcon,
BulletIcon,
PlusIcon,
GitHubIcon,
} from 'shared/components/icons.mjs'
import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs'
@ -43,6 +44,7 @@ export const icons = {
community: (className = '') => <CommunityIcon className={className} />,
sets: (className = '') => <MeasieIcon className={className} />,
patterns: (className = '') => <PageIcon className={className} />,
new: (className = '') => <PlusIcon className={className} />,
// Lab
code: (className = '') => <GitHubIcon className={className} />,

View file

@ -4,7 +4,7 @@ showcase: Showcase
showcaseAbout: Examples and inspiration from the FreeSewing community using our designs
docs: Documentation
docsAbout: In-depth documenation for all our designs, our website, and much more
account: Account
account: Your Account
accountAbout: Manage your account settings and preferences, and your presonal data
designs: Designs
designsAbout: Our library of designs that you can turn into made-to-measure patterns with a few clicks
@ -24,12 +24,12 @@ referenceAbout: Reference holds technical descriptions of the underlying technol
trainingAbout: Training materials are the most in-depth and strive to teach you a new skill.
mainSections: Main sections
currentSection: Current section
sets: Measurements Sets
patterns: Patterns
sets: Your Measurements Sets
patterns: Your Patterns
curate: Curate
curateSets: Curate Sets
code: Code
patternsAbout: Lists the patterns that you have stored in your FreeSewing account
setsAbout: Lists the measurements sets that you have stored in your FreeSewing account
codeAbout: Here you can find (links to) the Freesewing source code
new: New...

View file

@ -22,7 +22,7 @@ import { icons } from 'shared/components/navigation/primary.mjs'
*/
const onlyValidChildren = (tree, hIsOk = false) =>
orderBy(tree, ['o', 't'], ['asc', 'asc']).filter(
(entry) => typeof entry === 'object' && entry.t !== 'spacer' && !entry.h && !entry.m
(entry) => typeof entry === 'object' && entry.t !== 'spacer' && !entry.h
)
/*
@ -39,7 +39,7 @@ const onlyMainSections = (tree) =>
orderBy(tree, ['o', 't'], ['asc', 'asc']).filter((entry) => entry.m)
const SectionLink = ({ skey, tree, slug }) =>
tree[skey].s === slug ? (
tree[skey]._ ? null : tree[skey].s === slug ? ( // Underscore means always hide
<>
<span className="pl-2 border-l-2 py-2 block w-full border-secondary bg-opacity-10">
{tree[skey].t}
@ -189,7 +189,7 @@ export const NavLinks = ({ slug, siteNav, ignoreControl = false }) => (
{onlyValidChildren(siteNav).map((page, i) => (
<li key={i} className="w-full">
<MainLink s={page.s} t={page.t} slug={slug} />
{pageHasChildren(page) && <Section {...{ tree: page, slug }} />}
{pageHasChildren(page) && !page.n && <Section {...{ tree: page, slug }} />}
</li>
))}
</ul>

View file

@ -31,7 +31,7 @@ const NextPage = ({ t, s }) =>
<span></span>
)
export const PrevNext = ({ slug }) => {
export const PrevNext = ({ slug, noPrev = false }) => {
// Grab site navigation and slug lookup table from the useNavigatin hook
const { siteNav, slugLut } = useNavigation()
@ -42,13 +42,13 @@ export const PrevNext = ({ slug }) => {
const iNext = index === slugLut.length - 1 ? 0 : index + 1
// Subtract 1 for the previous page, unless it's the first page
const iPrev = index === 0 ? slugLut.length - 1 : index - 1
const iPrev = noPrev ? false : index === 0 ? slugLut.length - 1 : index - 1
// Get the next page from the siteNav object
const next = get(siteNav, slugLut[iNext].split('/'))
// Get the previous page from the siteNav object
const prev = get(siteNav, slugLut[iPrev].split('/'))
const prev = noPrev ? false : get(siteNav, slugLut[iPrev].split('/'))
// Return content
return (
@ -58,7 +58,7 @@ export const PrevNext = ({ slug }) => {
'items-start pt-6 mt-6 border-t-2 border-solid border-r-0 border-l-0 border-b-0'
}
>
<PrevPage t={prev.t} s={prev.s} />
{noPrev ? <span /> : <PrevPage t={prev.t} s={prev.s} />}
<NextPage t={next.t} s={next.s} />
</div>
)

View file

@ -12,6 +12,7 @@ export const LayoutWrapper = ({
setSearch,
noSearch = false,
header = false,
footer = true,
}) => {
const ChosenHeader = header ? header : Header
@ -70,7 +71,7 @@ export const LayoutWrapper = ({
<div className="fixed top-0 left-0 w-full min-h-screen bg-neutral z-20 bg-opacity-70"></div>
</>
)}
<Footer />
{footer && <Footer />}
</div>
)
}

View file

@ -30,11 +30,17 @@ export const PageWrapper = (props) => {
// Title is typically set in props.t but check props.title too
const pageTitle = props.t ? props.t : props.title ? props.title : null
/*
* Slug should come from page props.path not from context
* which won't be available in SSR
*/
const slug = path.join('/')
/*
* Contexts
*/
const { modalContent } = useContext(ModalContext)
const { setNavigation, slug } = useContext(NavigationContext)
const { setNavigation } = useContext(NavigationContext)
/*
* This forces a re-render upon initial bootstrap of the app
@ -73,7 +79,7 @@ export const PageWrapper = (props) => {
//const [search, setSearch] = useState(false)
// Helper object to pass props down (keeps things DRY)
const childProps = { footer, header, pageTitle }
const childProps = { footer, header, pageTitle, slug }
// Make layout prop into a (uppercase) component
const Layout = layout