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:
parent
8b79de2bd6
commit
5a9f2f8d40
26 changed files with 318 additions and 172 deletions
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
69
sites/org/components/layouts/docs.mjs
Normal file
69
sites/org/components/layouts/docs.mjs
Normal 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>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
export const ns = []
|
||||
|
||||
// This layout adds nothing
|
||||
export const NoLayout = ({ children = [] }) => children
|
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 && (
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
36
sites/shared/components/base-layout.mjs
Normal file
36
sites/shared/components/base-layout.mjs
Normal 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>
|
||||
)
|
|
@ -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 ''
|
||||
}
|
||||
|
|
|
@ -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} />,
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue