Merge branch 'develop' into eriese-lint-all
This commit is contained in:
commit
6cca85ada0
27 changed files with 448 additions and 462 deletions
|
@ -42,7 +42,7 @@ Now everybody knows this part requires the `head` measurement.
|
|||
|
||||
This change will also get picked up by the development environment, and you'll now see this screen:
|
||||
|
||||

|
||||

|
||||
|
||||
Since it's just one measurement, let's simply enter a value by hand.
|
||||
For example `38` as 38cm is a realistic head circumference measurement for a baby.
|
||||
|
|
|
@ -95,8 +95,6 @@
|
|||
"prettier": "^2.7.1",
|
||||
"pretty-quick": "^3.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"rehype-format": "^4.0.1",
|
||||
"remark": "^14.0.2",
|
||||
"remark-frontmatter": "^4.0.1",
|
||||
|
|
|
@ -12,7 +12,7 @@ const runTests = async (...params) => {
|
|||
//await apikeyTests(...params)
|
||||
//await accountTests(...params)
|
||||
//await personTests(...params)
|
||||
await patternTests(...params)
|
||||
//await patternTests(...params)
|
||||
}
|
||||
|
||||
// Load initial data required for tests
|
||||
|
|
|
@ -70,6 +70,7 @@ export const setup = async () => {
|
|||
console.log('Failed at account confirmation request', err)
|
||||
process.exit()
|
||||
}
|
||||
console.log(JSON.stringify(result.data, null ,2))
|
||||
store[acc].token = result.data.token
|
||||
store[acc].username = result.data.account.username
|
||||
store[acc].id = result.data.account.id
|
||||
|
|
|
@ -107,19 +107,12 @@ const Footer = ({ app }) => {
|
|||
<div className="lg:col-span-2 -order-2 2xl:order-2 px-4 lg:px-0">
|
||||
{/* Social icons */}
|
||||
<div className="w-full sm:w-auto flex flex-row flex-wrap gap-4 lg:gap-8 items-center justify-center">
|
||||
<Link href="/contact">
|
||||
<a
|
||||
className="hover:text-secondary hover:-mt-2 transition-all"
|
||||
title="Contact information"
|
||||
>
|
||||
<Link href="/contact" className="hover:text-secondary hover:-mt-2 transition-all" title="Contact information">
|
||||
<HelpIcon {...icon} />
|
||||
</a>
|
||||
</Link>
|
||||
{Object.keys(social).map((item) => (
|
||||
<Link key={item} href={social[item].href}>
|
||||
<a className="hover:text-secondary hover:-mt-2 transition-all" title={item}>
|
||||
<Link key={item} href={social[item].href} className="hover:text-secondary hover:-mt-2 transition-all" title={item}>
|
||||
{social[item].icon}
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -19,11 +19,7 @@ const DefaultLayout = ({ app, title = false, crumbs = false, children = [] }) =>
|
|||
slug={slug}
|
||||
before={[
|
||||
<div className="flex flex-row items-center justify-between border-b mb-4" key="home-key">
|
||||
<Link href="/">
|
||||
<a>
|
||||
<HomeIcon />
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/"><HomeIcon /></Link>
|
||||
<ThemePicker app={app} />
|
||||
</div>,
|
||||
]}
|
||||
|
|
|
@ -74,8 +74,8 @@ const SubLevel = ({ nodes = {}, active }) => (
|
|||
items-center
|
||||
`}
|
||||
>
|
||||
<Link href={`${child.__slug}`}>
|
||||
<a
|
||||
<Link
|
||||
href={`${child.__slug}`}
|
||||
title={child.__title}
|
||||
className={`
|
||||
grow pl-2 border-l-2
|
||||
|
@ -105,7 +105,6 @@ const SubLevel = ({ nodes = {}, active }) => (
|
|||
<span className={child.__slug === active ? 'font-bold' : ''}>
|
||||
{child.__linktitle || child.__title}
|
||||
</span>
|
||||
</a>
|
||||
</Link>
|
||||
<Chevron w={6} m={3} />
|
||||
</summary>
|
||||
|
@ -114,8 +113,9 @@ const SubLevel = ({ nodes = {}, active }) => (
|
|||
</li>
|
||||
) : (
|
||||
<li className="pl-2 flex flex-row items-center" key={child.__slug}>
|
||||
<Link href={`${child.__slug}`} title={child.__title}>
|
||||
<a
|
||||
<Link
|
||||
href={`${child.__slug}`}
|
||||
title={child.__title}
|
||||
className={`
|
||||
pl-2 border-l-2
|
||||
grow
|
||||
|
@ -144,7 +144,6 @@ const SubLevel = ({ nodes = {}, active }) => (
|
|||
<span className={child.__slug === active ? 'font-bold' : ''}>
|
||||
{child.__linktitle || child.__title}
|
||||
</span>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
|
@ -152,56 +151,6 @@ const SubLevel = ({ nodes = {}, active }) => (
|
|||
</ul>
|
||||
)
|
||||
|
||||
// Component that renders a toplevel of navigation
|
||||
/*
|
||||
const TopLevel = ({ icon, title, nav, current, slug, hasChildren=false, active }) => (
|
||||
<details className='py-1' open={0}>
|
||||
<summary className={`
|
||||
flex flex-row uppercase gap-4 font-bold text-lg
|
||||
hover:cursor-row-resize
|
||||
p-2
|
||||
text-base-content
|
||||
sm:text-base-content
|
||||
items-center
|
||||
`}>
|
||||
<span className="text-secondary">{icon}</span>
|
||||
<Link href={`${slug}`}>
|
||||
<a className={`
|
||||
grow ${linkClasses} hover:cursor-pointer
|
||||
${slug === active
|
||||
? 'text-secondary sm:text-secondary'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
</Link>
|
||||
{hasChildren && <Chevron />}
|
||||
</summary>
|
||||
{hasChildren && <SubLevel nodes={current} active={active} />}
|
||||
</details>
|
||||
)
|
||||
|
||||
const Navigation = ({ app, active, className='' }) => {
|
||||
if (!app.navigation) return null
|
||||
const output = []
|
||||
for (const page of order(app.navigation)) output.push(<TopLevel
|
||||
key={page.__slug}
|
||||
icon={icons[page.__slug]
|
||||
? icons[page.__slug]('w-6 h-6')
|
||||
: <span className="text-3xl mr-2 translate-y-3 inline-block p-0 leading-3">°</span>
|
||||
}
|
||||
title={page.__title}
|
||||
slug={page.__slug}
|
||||
hasChildren={1}
|
||||
nav={app.navigation}
|
||||
current={order(app.navigation[page.__slug])}
|
||||
active={active}
|
||||
/>)
|
||||
|
||||
return <div className={`pb-20 ${className}`}>{output}</div>
|
||||
}
|
||||
*/
|
||||
export const Icons = ({
|
||||
app,
|
||||
ulClasses = '',
|
||||
|
@ -215,11 +164,9 @@ export const Icons = ({
|
|||
for (const page of order(app.navigation)) {
|
||||
output.push(
|
||||
<li key={page.__slug}>
|
||||
<Link href={`${page.__slug}`}>
|
||||
<a className={linkClasses} title={page.__title} style={linkStyle}>
|
||||
<Link href={`${page.__slug}`} className={linkClasses} title={page.__title} style={linkStyle}>
|
||||
{icons[page.__slug] ? icons[page.__slug]('w-14 h-14') : <HelpIcon />}
|
||||
<span className="font-bold">{page.__title}</span>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
|
@ -227,16 +174,7 @@ export const Icons = ({
|
|||
|
||||
return <ul className={ulClasses}>{output}</ul>
|
||||
}
|
||||
/*
|
||||
const PrimaryMenu = ({ app, active, before=[], after=[] }) => (
|
||||
<nav className="mb-12">
|
||||
{before}
|
||||
<Icons app={app} ulClasses="hidden md:block lg:hidden flex flex-col items-center"/>
|
||||
<Navigation app={app} active={active} className="md:hidden lg:block"/>
|
||||
{after}
|
||||
</nav>
|
||||
)
|
||||
*/
|
||||
|
||||
export const MainSections = ({ app, active }) => {
|
||||
if (!app.navigation) return null
|
||||
const output = []
|
||||
|
@ -268,8 +206,8 @@ export const MainSections = ({ app, active }) => {
|
|||
{txt}
|
||||
</span>
|
||||
) : (
|
||||
<Link href={`${page.__slug}`}>
|
||||
<a
|
||||
<Link
|
||||
href={`${page.__slug}`}
|
||||
className={`${linkClasses}
|
||||
flex flex-row gap-4 items-center
|
||||
hover:bg-secondary hover:bg-opacity-10
|
||||
|
@ -278,7 +216,6 @@ export const MainSections = ({ app, active }) => {
|
|||
title={page.__title}
|
||||
>
|
||||
{txt}
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
</li>
|
||||
|
|
|
@ -67,8 +67,7 @@ const Hit = (props) => (
|
|||
${props.index === props.active ? 'bg-secondary bg-opacity-30' : 'bg-base-300 bg-opacity-10'}
|
||||
`}
|
||||
>
|
||||
<Link href={props.hit.page}>
|
||||
<a href={props.hit.page} className="flex flex-row justify-between gap-2">
|
||||
<Link href={props.hit.page} className="flex flex-row justify-between gap-2">
|
||||
<span className="text-base sm:text-xl font-bold leading-5">
|
||||
{props.hit._highlightResult?.title ? (
|
||||
<CustomHighlight hit={props.hit} attribute="title" />
|
||||
|
@ -79,20 +78,15 @@ const Hit = (props) => (
|
|||
<span className="text-xs pt-0.5 sm:text-base sm:pt-1 font-bold uppercase">
|
||||
{props.hit.page.split('/')[1]}
|
||||
</span>
|
||||
</a>
|
||||
</Link>
|
||||
{props.hit._snippetResult?.body && (
|
||||
<Link href={props.hit.page}>
|
||||
<a href={props.hit.page} className="text-sm sm:text-base block py-1">
|
||||
<Link href={props.hit.page} className="text-sm sm:text-base block py-1">
|
||||
<CustomHighlight hit={props.hit} attribute="body" snippet />
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
{props.hit?._highlightResult?.page && (
|
||||
<Link href={props.hit.page}>
|
||||
<a href={props.hit.page} className="text-xs sm:text-sm block opacity-70">
|
||||
<Link href={props.hit.page} className="text-xs sm:text-sm block opacity-70">
|
||||
<CustomHighlight hit={props.hit} attribute="page" />
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -25,21 +25,22 @@
|
|||
"serve": "pm2 start npm --name 'dev' -- run start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.0.1",
|
||||
"@mdx-js/loader": "^2.0.0-rc.2",
|
||||
"@mdx-js/mdx": "^2.0.0-rc.2",
|
||||
"@mdx-js/react": "^2.0.0-rc.2",
|
||||
"@mdx-js/runtime": "next",
|
||||
"@next/bundle-analyzer": "^13.0.5",
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"@heroicons/react": "latest",
|
||||
"@mdx-js/loader": "latest",
|
||||
"@mdx-js/mdx": "latest",
|
||||
"@mdx-js/react": "latest",
|
||||
"@mdx-js/runtime": "latest",
|
||||
"@next/bundle-analyzer": "^13",
|
||||
"@tailwindcss/typography": "latest",
|
||||
"algoliasearch": "^4.11.0",
|
||||
"daisyui": "^2.0.6",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.orderby": "^4.6.0",
|
||||
"lodash.set": "^4.3.2",
|
||||
"netlify-cli": "^12.0.4",
|
||||
"next": "latest",
|
||||
"next": "^13",
|
||||
"react": "^18.2.0",
|
||||
"react-copy-to-clipboard": "^5.0.4",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hotkeys-hook": "^3.4.4",
|
||||
"react-instantsearch-dom": "^6.18.0",
|
||||
"react-markdown": "^8.0.3",
|
||||
|
|
|
@ -48,9 +48,9 @@ const PatternPicker = ({ app }) => {
|
|||
{sectionPatterns(section).map((pattern) => (
|
||||
<li key={pattern}>
|
||||
<Link href={app.navigation[section][pattern].__slug}>
|
||||
<a className="capitalize pr-4 text-secondary hover:text-secondary-focus hover:underline">
|
||||
<span className="capitalize pr-4 text-secondary hover:text-secondary-focus hover:underline">
|
||||
{pattern}
|
||||
</a>
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
|
|
@ -110,10 +110,13 @@ const Footer = ({ app }) => {
|
|||
{/* Social icons */}
|
||||
<div className="w-full sm:w-auto flex flex-row flex-wrap gap-4 lg:gap-8 items-center justify-center">
|
||||
{Object.keys(social).map((item) => (
|
||||
<Link key={item} href={social[item].href}>
|
||||
<a className="hover:text-secondary hover:-mt-2 transition-all" title={item}>
|
||||
<Link
|
||||
key={item}
|
||||
href={social[item].href}
|
||||
className="hover:text-secondary hover:-mt-2 transition-all"
|
||||
title={item}
|
||||
>
|
||||
{social[item].icon}
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
"lodash.get": "^4.4.2",
|
||||
"lodash.orderby": "^4.6.0",
|
||||
"lodash.set": "^4.3.2",
|
||||
"netlify-cli": "^12.0.4",
|
||||
"next": "latest",
|
||||
"next-i18next": "^12.0.0",
|
||||
"react-copy-to-clipboard": "^5.0.4",
|
||||
|
|
|
@ -10,14 +10,17 @@ const DesignLinks = ({ list, prefix='' }) => {
|
|||
|
||||
return (
|
||||
<ul className="flex flex-col flex-wrap gap-2">
|
||||
{list.map( d => (
|
||||
{list.map((d) => (
|
||||
<li key={d} className="p-2">
|
||||
<Link href={`${prefix}/${d}`}>
|
||||
<a className="capitalize text-xl p-4 font-bold text-secondary hover:text-secondary-focus hover:underline">
|
||||
<Link
|
||||
href={`${prefix}/${d}`}
|
||||
className="capitalize text-xl p-4 font-bold text-secondary hover:text-secondary-focus hover:underline"
|
||||
>
|
||||
{t(`patterns:${d}.t`)}
|
||||
<br />
|
||||
<span className="text-lg font-normal p-4 text-base-content">{t(`patterns:${d}.d`)}</span>
|
||||
</a>
|
||||
<span className="text-lg font-normal p-4 text-base-content">
|
||||
{t(`patterns:${d}.d`)}
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
@ -29,9 +32,7 @@ const PatternListPageTemplate = ({ section=false }) => {
|
|||
const app = useApp()
|
||||
const { t } = useTranslation(['app'])
|
||||
|
||||
const title = section
|
||||
? app.navigation[section].__title
|
||||
: t('designs')
|
||||
const title = section ? app.navigation[section].__title : t('designs')
|
||||
|
||||
const sectionDesigns = (section = false) => {
|
||||
if (!section) {
|
||||
|
@ -47,7 +48,11 @@ const PatternListPageTemplate = ({ section=false }) => {
|
|||
<Page app={app} title={`FreeSewing Lab: ${title}`} layout={Layout}>
|
||||
<div className="max-w-7xl m-auto py-20 md:py-36 min-h-screen">
|
||||
<section className="px-8">
|
||||
<PageTitle app={app} slug={section ? app.navigation[section].__slug : '/' } title={title} />
|
||||
<PageTitle
|
||||
app={app}
|
||||
slug={section ? app.navigation[section].__slug : '/'}
|
||||
title={title}
|
||||
/>
|
||||
<DesignLinks list={sectionDesigns(section)} />
|
||||
</section>
|
||||
</div>
|
||||
|
@ -56,5 +61,3 @@ const PatternListPageTemplate = ({ section=false }) => {
|
|||
}
|
||||
|
||||
export default PatternListPageTemplate
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
"lodash.get": "^4.4.2",
|
||||
"lodash.orderby": "^4.6.0",
|
||||
"lodash.set": "^4.3.2",
|
||||
"netlify-cli": "^12.0.4",
|
||||
"next": "latest",
|
||||
"react-hotkeys-hook": "^3.4.4",
|
||||
"react-instantsearch-dom": "^6.18.0",
|
||||
|
|
|
@ -6,10 +6,8 @@ const Breadcrumbs = ({ crumbs = [], title }) =>
|
|||
crumbs ? (
|
||||
<ul className="flex flex-row flex-wrap gap-2 font-bold">
|
||||
<li>
|
||||
<Link href="/">
|
||||
<a title="FreeSewing" className="text-base-content">
|
||||
<Link href="/" title="FreeSewing" className="text-base-content">
|
||||
<FreeSewingIcon />
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{crumbs.map((crumb) => (
|
||||
|
@ -17,10 +15,12 @@ const Breadcrumbs = ({ crumbs = [], title }) =>
|
|||
<li className="text-base-content px-2">»</li>
|
||||
<li>
|
||||
{crumb[1] ? (
|
||||
<Link href={crumb[1]}>
|
||||
<a title={crumb[0]} className="text-secondary hover:text-secondary-focus">
|
||||
<Link
|
||||
href={crumb[1]}
|
||||
title={crumb[0]}
|
||||
className="text-secondary hover:text-secondary-focus"
|
||||
>
|
||||
{crumb[0]}
|
||||
</a>
|
||||
</Link>
|
||||
) : (
|
||||
<span className="text-base-content">{crumb[0]}</span>
|
||||
|
|
|
@ -27,32 +27,31 @@ const Breadcrumbs = ({ app, slug=false, title }) => {
|
|||
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)])
|
||||
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">
|
||||
<Link href="/" title="To the homepage" className="text-base-content">
|
||||
<Logo size={24} fill="currentColor" stroke={false} />
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{crumbs.map(crumb => (
|
||||
{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[2] ? (
|
||||
<Link
|
||||
href={crumb[1]}
|
||||
title={crumb[0]}
|
||||
className="text-secondary hover:text-secondary-focus"
|
||||
>
|
||||
{crumb[0]}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
: <span className="text-base-content">{crumb[0]}</span>
|
||||
}
|
||||
) : (
|
||||
<span className="text-base-content">{crumb[0]}</span>
|
||||
)}
|
||||
</li>
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
@ -78,7 +77,6 @@ const asideClasses = `
|
|||
xl:w-1/4
|
||||
`
|
||||
|
||||
|
||||
const DefaultLayout = ({
|
||||
app,
|
||||
title = false,
|
||||
|
@ -105,35 +103,44 @@ const DefaultLayout = ({
|
|||
const [collapseAltMenu, setCollapseAltMenu] = useState(false)
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
<div
|
||||
className={`
|
||||
flex flex-col justify-between
|
||||
min-h-screen
|
||||
bg-base-100
|
||||
`}>
|
||||
`}
|
||||
>
|
||||
<Header app={app} setSearch={setSearch} />
|
||||
<main className="grow bg-base-100">
|
||||
<div className="m-auto flex flex-row justify-center">
|
||||
|
||||
<aside className={`
|
||||
<aside
|
||||
className={`
|
||||
${asideClasses}
|
||||
${app.primaryMenu ? '' : 'translate-x-[-100%]'} transition-transform
|
||||
sm:flex-row-reverse
|
||||
${workbench && collapsePrimaryNav
|
||||
? 'sm:px-0 sm:w-16'
|
||||
: 'sm:px-1 md:px-4 lg:px-8'
|
||||
}
|
||||
${workbench && collapsePrimaryNav ? 'sm:px-0 sm:w-16' : 'sm:px-1 md:px-4 lg:px-8'}
|
||||
w-96
|
||||
`}>
|
||||
`}
|
||||
>
|
||||
{workbench && (
|
||||
<div className={`hidden sm:flex`}>
|
||||
<button
|
||||
className="text-secondary-focus h-full px-2 pl-4 hover:animate-pulse"
|
||||
onClick={() => setCollapsePrimaryNav(!collapsePrimaryNav)}
|
||||
>
|
||||
{collapsePrimaryNav
|
||||
? <><Right /><Right /><Right /></>
|
||||
: <><Left /><Left /><Left /></>
|
||||
}
|
||||
{collapsePrimaryNav ? (
|
||||
<>
|
||||
<Right />
|
||||
<Right />
|
||||
<Right />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Left />
|
||||
<Left />
|
||||
<Left />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
@ -141,14 +148,13 @@ const DefaultLayout = ({
|
|||
</aside>
|
||||
|
||||
<div className="p-0 m-0 bg-base-100">
|
||||
<section className={`
|
||||
<section
|
||||
className={`
|
||||
p-4 pt-24 sm:pt-28
|
||||
sm:px-1 md:px-4 lg:px-8
|
||||
${workbench && collapsePrimaryNav
|
||||
? ''
|
||||
: 'max-w-7xl'
|
||||
}
|
||||
`}>
|
||||
${workbench && collapsePrimaryNav ? '' : 'max-w-7xl'}
|
||||
`}
|
||||
>
|
||||
<div>
|
||||
{title && (
|
||||
<>
|
||||
|
@ -160,28 +166,35 @@ const DefaultLayout = ({
|
|||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{workbench && AltMenu && (
|
||||
<aside className={`
|
||||
<aside
|
||||
className={`
|
||||
${asideClasses}
|
||||
${app.primaryMenu ? '' : 'translate-x-[-100%]'} transition-transform
|
||||
sm:flex-row
|
||||
${collapseAltMenu
|
||||
? 'sm:px-0 sm:w-16'
|
||||
: 'sm:px-1 md:px-4 lg:px-8 sm:w-[38.2%]'
|
||||
}
|
||||
`}>
|
||||
${collapseAltMenu ? 'sm:px-0 sm:w-16' : 'sm:px-1 md:px-4 lg:px-8 sm:w-[38.2%]'}
|
||||
`}
|
||||
>
|
||||
<div className={`hidden sm:flex`}>
|
||||
<button
|
||||
className="text-secondary-focus h-full px-2 pr-4 hover:animate-pulse"
|
||||
onClick={() => setCollapseAltMenu(!collapseAltMenu)}
|
||||
>
|
||||
{collapseAltMenu
|
||||
? <><Left /><Left /><Left /></>
|
||||
: <><Right /><Right /><Right /></>
|
||||
}
|
||||
{collapseAltMenu ? (
|
||||
<>
|
||||
<Left />
|
||||
<Left />
|
||||
<Left />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Right />
|
||||
<Right />
|
||||
<Right />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
{AltMenu}
|
||||
|
@ -190,13 +203,15 @@ const DefaultLayout = ({
|
|||
</main>
|
||||
{!noSearch && search && (
|
||||
<>
|
||||
<div className={`
|
||||
<div
|
||||
className={`
|
||||
fixed w-full max-h-screen bg-base-100 top-0 z-30 pt-0 pb-16 px-8
|
||||
sm:rounded-lg sm:top-24
|
||||
sm:max-w-xl sm:m-auto sm: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>
|
||||
|
|
|
@ -48,8 +48,12 @@ const LocalePicker = ({ app, iconOnly = false, bottom = false }) => {
|
|||
<div className="overflow-hidden rounded-lg shadow-lg">
|
||||
<div className="relative grid gap-2 bg-base-100 p-4 grid-cols-1">
|
||||
{router.locales.map((locale) => (
|
||||
<Link href={`${locale}/${router.asPath}`} key={locale}>
|
||||
<a className="btn btn-primary">{t(locale)}</a>
|
||||
<Link
|
||||
href={`${locale}/${router.asPath}`}
|
||||
key={locale}
|
||||
className="btn btn-primary"
|
||||
>
|
||||
{t(locale)}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -76,8 +76,8 @@ const renderPrevious = (node) =>
|
|||
node ? (
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<LeftIcon className="w-6 h-6" />
|
||||
<Link href={'/' + node.__slug}>
|
||||
<a className="text-secondary break-words">{node.__linktitle}</a>
|
||||
<Link href={'/' + node.__slug} className="text-secondary break-words">
|
||||
{node.__linktitle}
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
|
@ -87,8 +87,8 @@ const renderPrevious = (node) =>
|
|||
const renderNext = (node) =>
|
||||
node ? (
|
||||
<div className="flex flex-row gap-2 items-center justify-end">
|
||||
<Link href={'/' + node.__slug}>
|
||||
<a className="text-right break-words">{node.__linktitle}</a>
|
||||
<Link href={'/' + node.__slug} className="text-right break-words">
|
||||
{node.__linktitle}
|
||||
</Link>
|
||||
<RightIcon className="w-6 h-6" />
|
||||
</div>
|
||||
|
|
|
@ -3,26 +3,30 @@ import orderBy from 'lodash.orderby'
|
|||
import Link from 'next/link'
|
||||
|
||||
// Helper method to filter out the real children
|
||||
const order = obj => orderBy(obj, ['__order', '__title'], ['asc', 'asc'])
|
||||
const currentChildren = current => Object.values(order(current))
|
||||
.filter(entry => (typeof entry === 'object'))
|
||||
const order = (obj) => orderBy(obj, ['__order', '__title'], ['asc', 'asc'])
|
||||
const currentChildren = (current) =>
|
||||
Object.values(order(current)).filter((entry) => typeof entry === 'object')
|
||||
|
||||
const ReadMore = props => {
|
||||
const ReadMore = (props) => {
|
||||
// Don't bother if we don't have the navigation tree in app
|
||||
if (!props.app) return null
|
||||
|
||||
const root = get(props.app.navigation, props.slug.split('/'))
|
||||
const list = []
|
||||
for (const page of currentChildren(root)) {
|
||||
list.push(<li key={page.__slug} className={props.recurse ? 'ont-bold' : ''}>
|
||||
<Link href={`/${page.__slug}`}>
|
||||
<a className={props.recurse ? 'inline-block font-bold pt-3 pb-1' : ''}>{page.__title}</a>
|
||||
list.push(
|
||||
<li key={page.__slug} className={props.recurse ? 'ont-bold' : ''}>
|
||||
<Link
|
||||
href={`/${page.__slug}`}
|
||||
className={props.recurse ? 'inline-block font-bold pt-3 pb-1' : ''}
|
||||
>
|
||||
{page.__title}
|
||||
</Link>
|
||||
{props.recurse && <ReadMore app={props.app} slug={page.__slug} />}
|
||||
</li>)
|
||||
</li>
|
||||
)
|
||||
}
|
||||
return <ul>{list}</ul>
|
||||
}
|
||||
|
||||
export default ReadMore
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import CommunityIcon from 'shared/components/icons/community.js'
|
|||
import ShowcaseIcon from 'shared/components/icons/camera.js'
|
||||
|
||||
// Don't show children for blog and showcase posts
|
||||
const keepClosed = ['blog', 'showcase', ]
|
||||
const keepClosed = ['blog', 'showcase']
|
||||
|
||||
// List of icons matched to top-level slug
|
||||
const icons = {
|
||||
|
@ -34,21 +34,26 @@ const icons = {
|
|||
}
|
||||
|
||||
/* helper method to order nav entries */
|
||||
const order = obj => orderBy(obj, ['__order', '__title'], ['asc', 'asc'])
|
||||
const order = (obj) => orderBy(obj, ['__order', '__title'], ['asc', 'asc'])
|
||||
|
||||
// Component for the collapse toggle
|
||||
// Exported for re-use
|
||||
export const Chevron = ({w=8, m=2}) => <svg className={`
|
||||
export const Chevron = ({ w = 8, m = 2 }) => (
|
||||
<svg
|
||||
className={`
|
||||
fill-current opacity-75 w-${w} h-${w} mr-${m}
|
||||
details-toggle hover:text-secondary sm:hover:text-secondary
|
||||
`}
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path d="M12.95 10.707l.707-.707L8 4.343 6.586 5.757 10.828 10l-4.242 4.243L8 15.657l4.95-4.95z" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
// Helper method to filter out the real children
|
||||
const currentChildren = current => Object.values(order(current))
|
||||
.filter(entry => (typeof entry === 'object'))
|
||||
const currentChildren = (current) =>
|
||||
Object.values(order(current)).filter((entry) => typeof entry === 'object')
|
||||
|
||||
// Shared classes for links
|
||||
// Exported for re-use
|
||||
|
@ -75,43 +80,52 @@ const isActive = (slug, active) => {
|
|||
// Component that renders a sublevel of navigation
|
||||
const SubLevel = ({ nodes = {}, active }) => (
|
||||
<ul className="pl-5 list-inside">
|
||||
{currentChildren(nodes).map(child => (Object.keys(child).length > 4)
|
||||
? (
|
||||
{currentChildren(nodes).map((child) =>
|
||||
Object.keys(child).length > 4 ? (
|
||||
<li key={child.__slug} className="flex flex-row">
|
||||
<details className="grow" open={isActive(child.__slug, active)}>
|
||||
<summary className={`
|
||||
<summary
|
||||
className={`
|
||||
flex flex-row
|
||||
px-2
|
||||
text-base-content
|
||||
sm:text-base-content
|
||||
hover:cursor-row-resize
|
||||
items-center
|
||||
`}>
|
||||
<Link href={`${child.__slug}`}>
|
||||
<a title={child.__title} className={`
|
||||
`}
|
||||
>
|
||||
<Link
|
||||
href={`${child.__slug}`}
|
||||
title={child.__title}
|
||||
className={`
|
||||
grow pl-2 border-l-2
|
||||
${linkClasses}
|
||||
hover:cursor-pointer
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary
|
||||
${child.__slug === active
|
||||
${
|
||||
child.__slug === active
|
||||
? 'text-secondary border-secondary sm:text-secondary sm:border-secondary'
|
||||
: 'text-base-content sm:text-base-content'
|
||||
}
|
||||
`}>
|
||||
<span className={`
|
||||
`}
|
||||
>
|
||||
<span className={linkClasses}>
|
||||
<span
|
||||
className={`
|
||||
text-3xl mr-2 inline-block p-0 leading-3
|
||||
${child.__slug === active
|
||||
${
|
||||
child.__slug === active
|
||||
? 'text-secondary sm:text-secondary translate-y-1'
|
||||
: 'translate-y-3'
|
||||
}
|
||||
`}>
|
||||
`}
|
||||
>
|
||||
{child.__slug === active ? <>•</> : <>°</>}
|
||||
</span>
|
||||
<span className={child.__slug === active ? 'font-bold' : ''}>
|
||||
{child.__linktitle || child.__title}
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
</Link>
|
||||
<Chevron w={6} m={3} />
|
||||
</summary>
|
||||
|
@ -119,62 +133,67 @@ const SubLevel = ({ nodes={}, active }) => (
|
|||
</details>
|
||||
</li>
|
||||
) : (
|
||||
<li className='pl-2 flex flex-row items-center' key={child.__slug}>
|
||||
<Link href={`${child.__slug}`} title={child.__title}>
|
||||
<a className={`
|
||||
<li className="pl-2 flex flex-row items-center" key={child.__slug}>
|
||||
<Link
|
||||
href={`${child.__slug}`}
|
||||
title={child.__title}
|
||||
className={`
|
||||
pl-2 border-l-2
|
||||
grow
|
||||
${linkClasses}
|
||||
hover:cursor-pointer
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary
|
||||
${child.__slug === active
|
||||
${
|
||||
child.__slug === active
|
||||
? 'text-secondary border-secondary sm:text-secondary sm:border-secondary'
|
||||
: 'text-base-content sm:text-base-content'
|
||||
}`}>
|
||||
<span className={`
|
||||
}`}
|
||||
>
|
||||
<span className={linkClasses}>
|
||||
<span
|
||||
className={`
|
||||
text-3xl mr-2 inline-block p-0 leading-3
|
||||
${child.__slug === active
|
||||
${
|
||||
child.__slug === active
|
||||
? 'text-secondary sm:text-secondary translate-y-1'
|
||||
: 'translate-y-3'
|
||||
}
|
||||
`}>
|
||||
`}
|
||||
>
|
||||
{child.__slug === active ? <>•</> : <>°</>}
|
||||
</span>
|
||||
<span className={child.__slug === active ? 'font-bold' : ''}>
|
||||
{child.__linktitle || child.__title}
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
|
||||
)}
|
||||
</ul>
|
||||
)
|
||||
|
||||
// Component that renders a toplevel of navigation
|
||||
const TopLevel = ({ icon, title, nav, current, slug, hasChildren = false, active }) => (
|
||||
<details className='py-1' open={((keepClosed.indexOf(current.__slug) === -1) ? 1 : 0)}>
|
||||
<summary className={`
|
||||
<details className="py-1" open={keepClosed.indexOf(current.__slug) === -1 ? 1 : 0}>
|
||||
<summary
|
||||
className={`
|
||||
flex flex-row uppercase gap-4 font-bold text-lg
|
||||
hover:cursor-row-resize
|
||||
p-2
|
||||
text-base-content
|
||||
sm:text-base-content
|
||||
items-center
|
||||
`}>
|
||||
`}
|
||||
>
|
||||
<span className="text-secondary">{icon}</span>
|
||||
<Link href={`${slug}`}>
|
||||
<a className={`
|
||||
<Link
|
||||
href={`${slug}`}
|
||||
className={`
|
||||
grow ${linkClasses} hover:cursor-pointer
|
||||
${slug === active
|
||||
? 'text-secondary sm:text-secondary'
|
||||
: ''
|
||||
}`}
|
||||
${slug === active ? 'text-secondary sm:text-secondary' : ''}`}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
</Link>
|
||||
{hasChildren && <Chevron />}
|
||||
</summary>
|
||||
|
@ -185,11 +204,16 @@ const TopLevel = ({ icon, title, nav, current, slug, hasChildren=false, active }
|
|||
const Navigation = ({ app, active, className = '' }) => {
|
||||
if (!app.navigation) return null
|
||||
const output = []
|
||||
for (const page of order(app.navigation)) output.push(<TopLevel
|
||||
for (const page of order(app.navigation))
|
||||
output.push(
|
||||
<TopLevel
|
||||
key={page.__slug}
|
||||
icon={icons[page.__slug]
|
||||
? icons[page.__slug]('w-6 h-6')
|
||||
: <span className="text-3xl mr-2 translate-y-3 inline-block p-0 leading-3">°</span>
|
||||
icon={
|
||||
icons[page.__slug] ? (
|
||||
icons[page.__slug]('w-6 h-6')
|
||||
) : (
|
||||
<span className="text-3xl mr-2 translate-y-3 inline-block p-0 leading-3">°</span>
|
||||
)
|
||||
}
|
||||
title={page.__title}
|
||||
slug={page.__slug}
|
||||
|
@ -197,33 +221,32 @@ const Navigation = ({ app, active, className='' }) => {
|
|||
nav={app.navigation}
|
||||
current={order(app.navigation[page.__slug])}
|
||||
active={active}
|
||||
/>)
|
||||
/>
|
||||
)
|
||||
|
||||
return <div className={`pb-20 ${className}`}>{output}</div>
|
||||
}
|
||||
|
||||
export const Icons = ({
|
||||
app, active,
|
||||
app,
|
||||
active,
|
||||
ulClasses = '',
|
||||
liClasses = '',
|
||||
linkClasses = `grow text-lg lg:text-xl py-1 text-base-content sm:text-base-content
|
||||
hover:text-secondary sm:hover:text-secondary hover:cursor-pointer
|
||||
flex flex-col items-center`,
|
||||
linkStyle={}
|
||||
linkStyle = {},
|
||||
}) => {
|
||||
if (!app.navigation) return null
|
||||
const output = []
|
||||
for (const page of order(app.navigation)) {
|
||||
output.push(
|
||||
<li key={page.__slug} className={liClasses}>
|
||||
<Link href={`${page.__slug}`}>
|
||||
<a className={linkClasses} title={page.__title} style={linkStyle}>
|
||||
{icons[page.__slug]
|
||||
? icons[page.__slug]('w-14 h-14')
|
||||
: <HelpIcon />
|
||||
}
|
||||
<span className='font-bold'>{page.__title}</span>
|
||||
</a>
|
||||
<Link href={`${page.__slug}`} title={page.__title} style={linkStyle}>
|
||||
<span className={linkClasses}>
|
||||
{icons[page.__slug] ? icons[page.__slug]('w-14 h-14') : <HelpIcon />}
|
||||
<span className="font-bold">{page.__title}</span>
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
const PageLink = ({ href, txt, className="" }) => (
|
||||
<Link href={href}>
|
||||
<a className={`font-bold text-secondary
|
||||
hover:text-secondary-focus hover:underline ${className}`}
|
||||
title={txt}>{txt}</a>
|
||||
const PageLink = ({ href, txt, className = '' }) => (
|
||||
<Link
|
||||
href={href}
|
||||
className={`font-bold text-secondary hover:text-secondary-focus hover:underline ${className}`}
|
||||
title={txt}
|
||||
>
|
||||
{txt}
|
||||
</Link>
|
||||
)
|
||||
|
||||
export default PageLink
|
||||
|
||||
|
|
|
@ -4,25 +4,35 @@ import Link from 'next/link'
|
|||
|
||||
/** an accessible dropdown menu for use by picker components */
|
||||
export const Picker = ({ Icon, className, title, ariaLabel, iconOnly = false, children, end }) => {
|
||||
|
||||
return (<Menu as="div" className={`w-auto relative`}>
|
||||
<Menu.Button className={iconOnly
|
||||
return (
|
||||
<Menu as="div" className={`w-auto relative`}>
|
||||
<Menu.Button
|
||||
className={
|
||||
iconOnly
|
||||
? `btn btn-sm`
|
||||
: `m-0 btn btn-neutral flex flex-row gap-2
|
||||
hover:bg-neutral-focus
|
||||
`}
|
||||
aria-label={ariaLabel}>
|
||||
`
|
||||
}
|
||||
aria-label={ariaLabel}
|
||||
>
|
||||
<Icon />
|
||||
{!iconOnly && <span>{title}</span>}
|
||||
</Menu.Button>
|
||||
<Menu.Items as="ul" className={`p-2 shadow menu bg-base-100 rounded-box w-52 ${className} absolute ${end ? 'right-0' : 'left-0'} top-full mt-1`}>
|
||||
<Menu.Items
|
||||
as="ul"
|
||||
className={`p-2 shadow menu bg-base-100 rounded-box w-52 ${className} absolute ${
|
||||
end ? 'right-0' : 'left-0'
|
||||
} top-full mt-1`}
|
||||
>
|
||||
{children}
|
||||
</Menu.Items>
|
||||
</Menu>)
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
/** get the menu item's class based on whether it's active */
|
||||
const itemClass = (active) => "btn btn-ghost " + (active ? 'bg-base-200' : '')
|
||||
const itemClass = (active) => 'btn btn-ghost ' + (active ? 'bg-base-200' : '')
|
||||
|
||||
/**
|
||||
* a menu item that has a link in it
|
||||
|
@ -32,34 +42,39 @@ const itemClass = (active) => "btn btn-ghost " + (active ? 'bg-base-200' : '')
|
|||
** locale?: the locale the link links to
|
||||
* */
|
||||
export const PickerLink = (props) => {
|
||||
return (<li role="menuitem">
|
||||
return (
|
||||
<li role="menuitem">
|
||||
<Menu.Item>
|
||||
{({active}) => (<ForwardLink active={active} {...props}></ForwardLink>)}
|
||||
{({ active }) => <ForwardLink active={active} {...props}></ForwardLink>}
|
||||
</Menu.Item>
|
||||
</li>)
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Necessary to have keyboard enter 'click' events passed to the link */
|
||||
const ForwardLink = forwardRef(({ href, locale, active, children, ...rest }, ref) => (
|
||||
<Link href={href} locale={locale}>
|
||||
<a className={itemClass(active)} {...rest} role={undefined} ref={ref}>
|
||||
<span className="text-base-content">
|
||||
{children}
|
||||
</span>
|
||||
</a>
|
||||
<Link
|
||||
href={href}
|
||||
locale={locale}
|
||||
className={itemClass(active)}
|
||||
{...rest}
|
||||
role={undefined}
|
||||
ref={ref}
|
||||
>
|
||||
<span className="text-base-content">{children}</span>
|
||||
</Link>
|
||||
))
|
||||
|
||||
/** a menu item that is a button */
|
||||
export const PickerButton = ({ onClick, children }) => {
|
||||
return (<Menu.Item as="li" onClick={onClick}>
|
||||
return (
|
||||
<Menu.Item as="li" onClick={onClick}>
|
||||
{({ active }) => (
|
||||
<button className={itemClass(active)}>
|
||||
<span className="text-base-content">
|
||||
{children}
|
||||
</span>
|
||||
<span className="text-base-content">{children}</span>
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>)
|
||||
</Menu.Item>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,12 +16,11 @@ export const InnerWordMark = () => (
|
|||
)
|
||||
|
||||
export const WordMark = () => (
|
||||
<Link href="/">
|
||||
<a
|
||||
<Link
|
||||
href="/"
|
||||
role="button"
|
||||
className="btn btn-ghost btn-sm normal-case text-2xl hover:bg-transparent font-bold px-0 -mt-1"
|
||||
>
|
||||
<InnerWordMark />
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
|
|
|
@ -25,7 +25,7 @@ const PreviewTile = ({ img, slug, title, href=false, fixed=false }) => (
|
|||
>
|
||||
{href
|
||||
? <a href={href} title={title} className={linkClasses(fixed)}/>
|
||||
: <Link href={slug}><a title={title} className={linkClasses(fixed)}/></Link>
|
||||
: <Link href={slug} title={title} className={linkClasses(fixed)}></Link>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useState, useEffect } from 'react'
|
|||
|
||||
// See: https://mdxjs.com/guides/mdx-on-demand/
|
||||
import { run } from '@mdx-js/mdx'
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
import * as runtime from 'react/jsx-runtime'
|
||||
|
||||
// Components that are available in all MDX
|
||||
import customComponents from 'shared/components/mdx'
|
||||
|
@ -18,7 +18,6 @@ import PrevNext from '../mdx/prev-next'
|
|||
const Null = (props) => null
|
||||
|
||||
const MdxWrapper = ({ mdx, app, t, components = {} }) => {
|
||||
|
||||
const [mdxModule, setMdxModule] = useState()
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -34,20 +33,20 @@ const MdxWrapper = ({mdx, app, t, components={}}) => {
|
|||
*/
|
||||
const allComponents = {
|
||||
...customComponents(app, t),
|
||||
...components
|
||||
...components,
|
||||
}
|
||||
|
||||
// React component for MDX content
|
||||
const MdxContent = mdxModule ? mdxModule.default : Null
|
||||
|
||||
return app
|
||||
? (
|
||||
return app ? (
|
||||
<div className="text-primary mdx max-w-prose text-base-content max-w-prose text-lg lg:text-xl">
|
||||
{mdxModule && <MdxContent components={allComponents} />}
|
||||
<PrevNext app={app} />
|
||||
</div>
|
||||
) : <MdxContent components={allComponents}/>
|
||||
) : (
|
||||
<MdxContent components={allComponents} />
|
||||
)
|
||||
}
|
||||
|
||||
export default MdxWrapper
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useState, useEffect, Fragment } from 'react'
|
|||
|
||||
// See: https://mdxjs.com/guides/mdx-on-demand/
|
||||
import { run } from '@mdx-js/mdx'
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
import * as runtime from 'react/jsx-runtime'
|
||||
|
||||
const TocWrapper = ({ toc, app }) => {
|
||||
const [mdxModule, setMdxModule] = useState()
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
"mdast-util-toc": "^6.1.0",
|
||||
"pdfkit": "^0.13.0",
|
||||
"postcss-for": "^2.1.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-markdown": "^8.0.0",
|
||||
"react-sizeme": "^3.0.2",
|
||||
"react-timeago": "^7.1.0",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue