2021-12-12 18:58:24 +01:00
|
|
|
import Link from 'next/link'
|
2021-12-16 19:01:37 +01:00
|
|
|
import orderBy from 'lodash.orderby'
|
2023-01-28 19:27:11 +01:00
|
|
|
import {
|
|
|
|
RssIcon,
|
|
|
|
TutorialIcon,
|
|
|
|
GuideIcon,
|
|
|
|
HelpIcon,
|
|
|
|
DocsIcon,
|
|
|
|
DesignIcon,
|
|
|
|
BoxIcon,
|
|
|
|
CogIcon,
|
|
|
|
UserIcon,
|
|
|
|
CommunityIcon,
|
|
|
|
ShowcaseIcon,
|
|
|
|
} from 'shared/components/icons.mjks'
|
2021-12-11 14:04:05 +01:00
|
|
|
|
2021-12-17 17:51:20 +01:00
|
|
|
// Don't show children for blog and showcase posts
|
2022-12-04 15:04:56 +01:00
|
|
|
const keepClosed = ['blog', 'showcase']
|
2021-12-12 18:58:24 +01:00
|
|
|
|
2021-12-27 14:30:10 +01:00
|
|
|
// List of icons matched to top-level slug
|
|
|
|
const icons = {
|
2022-12-04 15:04:56 +01:00
|
|
|
accessories: (className = '') => <TutorialIcon className={className} />,
|
|
|
|
account: (className = '') => <UserIcon className={className} />,
|
|
|
|
blocks: (className = '') => <BoxIcon className={className} />,
|
|
|
|
blog: (className = '') => <RssIcon className={className} />,
|
|
|
|
community: (className = '') => <CommunityIcon className={className} />,
|
|
|
|
designs: (className = '') => <DesignIcon className={className} />,
|
|
|
|
docs: (className = '') => <DocsIcon className={className} />,
|
|
|
|
garments: (className = '') => <DesignIcon className={className} />,
|
|
|
|
guides: (className = '') => <GuideIcon className={className} />,
|
|
|
|
howtos: (className = '') => <HelpIcon className={className} />,
|
|
|
|
reference: (className = '') => <DocsIcon className={className} />,
|
|
|
|
showcase: (className = '') => <ShowcaseIcon className={className} />,
|
|
|
|
tutorials: (className = '') => <TutorialIcon className={className} />,
|
|
|
|
utilities: (className = '') => <CogIcon className={className} />,
|
2021-12-27 14:30:10 +01:00
|
|
|
}
|
|
|
|
|
2021-12-25 13:43:41 +01:00
|
|
|
/* helper method to order nav entries */
|
2022-12-04 15:04:56 +01:00
|
|
|
const order = (obj) => orderBy(obj, ['__order', '__title'], ['asc', 'asc'])
|
2021-12-25 13:43:41 +01:00
|
|
|
|
2021-12-17 17:51:20 +01:00
|
|
|
// Component for the collapse toggle
|
2022-01-22 17:55:03 +01:00
|
|
|
// Exported for re-use
|
2022-12-04 15:04:56 +01:00
|
|
|
export const Chevron = ({ w = 8, m = 2 }) => (
|
|
|
|
<svg
|
|
|
|
className={`
|
2021-12-30 18:42:49 +01:00
|
|
|
fill-current opacity-75 w-${w} h-${w} mr-${m}
|
2022-05-11 16:29:46 +02:00
|
|
|
details-toggle hover:text-secondary sm:hover:text-secondary
|
2021-12-30 18:42:49 +01:00
|
|
|
`}
|
2022-12-04 15:04:56 +01:00
|
|
|
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>
|
|
|
|
)
|
2021-12-17 17:51:20 +01:00
|
|
|
|
|
|
|
// Helper method to filter out the real children
|
2022-12-04 15:04:56 +01:00
|
|
|
const currentChildren = (current) =>
|
|
|
|
Object.values(order(current)).filter((entry) => typeof entry === 'object')
|
2021-12-16 19:01:37 +01:00
|
|
|
|
2021-12-21 20:47:13 +01:00
|
|
|
// Shared classes for links
|
2022-01-22 17:55:03 +01:00
|
|
|
// Exported for re-use
|
|
|
|
export const linkClasses = `text-lg lg:text-xl
|
2022-01-27 18:07:37 +01:00
|
|
|
py-1
|
2022-05-11 16:29:46 +02:00
|
|
|
text-base-content sm:text-base-content
|
2021-12-30 18:42:49 +01:00
|
|
|
hover:text-secondary
|
2022-05-11 16:29:46 +02:00
|
|
|
sm:hover:text-secondary
|
2021-12-30 18:42:49 +01:00
|
|
|
`
|
2021-12-21 18:50:19 +01:00
|
|
|
|
2021-12-22 17:11:49 +01:00
|
|
|
// Figure out whether a page is on the path to the active page
|
|
|
|
const isActive = (slug, active) => {
|
|
|
|
if (slug === active) return true
|
|
|
|
let result = true
|
|
|
|
const slugParts = slug.split('/')
|
|
|
|
const activeParts = active.split('/')
|
|
|
|
for (const i in slugParts) {
|
|
|
|
if (slugParts[i] !== activeParts[i]) result = false
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-12-17 17:51:20 +01:00
|
|
|
// Component that renders a sublevel of navigation
|
2022-12-04 15:04:56 +01:00
|
|
|
const SubLevel = ({ nodes = {}, active }) => (
|
2021-12-21 20:47:13 +01:00
|
|
|
<ul className="pl-5 list-inside">
|
2022-12-04 15:04:56 +01:00
|
|
|
{currentChildren(nodes).map((child) =>
|
|
|
|
Object.keys(child).length > 4 ? (
|
2021-12-21 20:47:13 +01:00
|
|
|
<li key={child.__slug} className="flex flex-row">
|
2021-12-22 17:11:49 +01:00
|
|
|
<details className="grow" open={isActive(child.__slug, active)}>
|
2022-12-04 15:04:56 +01:00
|
|
|
<summary
|
|
|
|
className={`
|
2021-12-21 20:47:13 +01:00
|
|
|
flex flex-row
|
|
|
|
px-2
|
2021-12-30 18:42:49 +01:00
|
|
|
text-base-content
|
2022-05-11 16:29:46 +02:00
|
|
|
sm:text-base-content
|
2021-12-17 17:51:20 +01:00
|
|
|
hover:cursor-row-resize
|
2021-12-21 20:47:13 +01:00
|
|
|
items-center
|
2022-12-04 15:04:56 +01:00
|
|
|
`}
|
|
|
|
>
|
|
|
|
<Link
|
|
|
|
href={`${child.__slug}`}
|
|
|
|
title={child.__title}
|
|
|
|
className={`
|
2021-12-22 17:06:50 +01:00
|
|
|
grow pl-2 border-l-2
|
2022-01-27 18:07:37 +01:00
|
|
|
hover:cursor-pointer
|
2021-12-30 18:42:49 +01:00
|
|
|
hover:border-secondary
|
2022-05-11 16:29:46 +02:00
|
|
|
sm:hover:border-secondary
|
2022-12-04 15:04:56 +01:00
|
|
|
${
|
|
|
|
child.__slug === active
|
|
|
|
? 'text-secondary border-secondary sm:text-secondary sm:border-secondary'
|
|
|
|
: 'text-base-content sm:text-base-content'
|
2021-12-30 18:42:49 +01:00
|
|
|
}
|
2022-12-04 15:04:56 +01:00
|
|
|
`}
|
|
|
|
>
|
|
|
|
<span className={linkClasses}>
|
|
|
|
<span
|
|
|
|
className={`
|
|
|
|
text-3xl mr-2 inline-block p-0 leading-3
|
|
|
|
${
|
|
|
|
child.__slug === active
|
|
|
|
? 'text-secondary sm:text-secondary translate-y-1'
|
|
|
|
: 'translate-y-3'
|
|
|
|
}
|
|
|
|
`}
|
|
|
|
>
|
2021-12-27 14:30:10 +01:00
|
|
|
{child.__slug === active ? <>•</> : <>°</>}
|
|
|
|
</span>
|
|
|
|
<span className={child.__slug === active ? 'font-bold' : ''}>
|
2022-12-04 15:04:56 +01:00
|
|
|
{child.__linktitle || child.__title}
|
2021-12-27 14:30:10 +01:00
|
|
|
</span>
|
2022-12-04 15:04:56 +01:00
|
|
|
</span>
|
2021-12-21 20:47:13 +01:00
|
|
|
</Link>
|
2022-12-04 15:04:56 +01:00
|
|
|
<Chevron w={6} m={3} />
|
2021-12-17 17:51:20 +01:00
|
|
|
</summary>
|
2021-12-22 17:06:50 +01:00
|
|
|
<SubLevel nodes={child} active={active} />
|
2021-12-17 17:51:20 +01:00
|
|
|
</details>
|
|
|
|
</li>
|
|
|
|
) : (
|
2022-12-04 15:04:56 +01:00
|
|
|
<li className="pl-2 flex flex-row items-center" key={child.__slug}>
|
|
|
|
<Link
|
|
|
|
href={`${child.__slug}`}
|
|
|
|
title={child.__title}
|
|
|
|
className={`
|
2021-12-22 17:06:50 +01:00
|
|
|
pl-2 border-l-2
|
2021-12-30 18:42:49 +01:00
|
|
|
grow
|
2022-01-27 18:07:37 +01:00
|
|
|
hover:cursor-pointer
|
2021-12-30 18:42:49 +01:00
|
|
|
hover:border-secondary
|
2022-05-11 16:29:46 +02:00
|
|
|
sm:hover:border-secondary
|
2022-12-04 15:04:56 +01:00
|
|
|
${
|
|
|
|
child.__slug === active
|
|
|
|
? 'text-secondary border-secondary sm:text-secondary sm:border-secondary'
|
|
|
|
: 'text-base-content sm:text-base-content'
|
|
|
|
}`}
|
|
|
|
>
|
|
|
|
<span className={linkClasses}>
|
|
|
|
<span
|
|
|
|
className={`
|
|
|
|
text-3xl mr-2 inline-block p-0 leading-3
|
|
|
|
${
|
|
|
|
child.__slug === active
|
|
|
|
? 'text-secondary sm:text-secondary translate-y-1'
|
|
|
|
: 'translate-y-3'
|
|
|
|
}
|
|
|
|
`}
|
|
|
|
>
|
|
|
|
{child.__slug === active ? <>•</> : <>°</>}
|
2021-12-27 14:30:10 +01:00
|
|
|
</span>
|
|
|
|
<span className={child.__slug === active ? 'font-bold' : ''}>
|
2022-07-15 16:44:10 -04:00
|
|
|
{child.__linktitle || child.__title}
|
2021-12-27 14:30:10 +01:00
|
|
|
</span>
|
2022-12-04 15:04:56 +01:00
|
|
|
</span>
|
2021-12-17 17:51:20 +01:00
|
|
|
</Link>
|
|
|
|
</li>
|
|
|
|
)
|
|
|
|
)}
|
|
|
|
</ul>
|
|
|
|
)
|
2021-12-16 19:01:37 +01:00
|
|
|
|
2021-12-17 17:51:20 +01:00
|
|
|
// Component that renders a toplevel of navigation
|
2022-12-04 15:04:56 +01:00
|
|
|
const TopLevel = ({ icon, title, nav, current, slug, hasChildren = false, active }) => (
|
|
|
|
<details className="py-1" open={keepClosed.indexOf(current.__slug) === -1 ? 1 : 0}>
|
|
|
|
<summary
|
|
|
|
className={`
|
2021-12-12 18:58:24 +01:00
|
|
|
flex flex-row uppercase gap-4 font-bold text-lg
|
|
|
|
hover:cursor-row-resize
|
|
|
|
p-2
|
2021-12-30 18:42:49 +01:00
|
|
|
text-base-content
|
2022-05-11 16:29:46 +02:00
|
|
|
sm:text-base-content
|
2021-12-21 18:50:19 +01:00
|
|
|
items-center
|
2022-12-04 15:04:56 +01:00
|
|
|
`}
|
|
|
|
>
|
2022-05-11 16:29:46 +02:00
|
|
|
<span className="text-secondary">{icon}</span>
|
2022-12-04 15:04:56 +01:00
|
|
|
<Link
|
|
|
|
href={`${slug}`}
|
|
|
|
className={`
|
2022-01-27 18:07:37 +01:00
|
|
|
grow ${linkClasses} hover:cursor-pointer
|
2022-12-04 15:04:56 +01:00
|
|
|
${slug === active ? 'text-secondary sm:text-secondary' : ''}`}
|
|
|
|
>
|
|
|
|
{title}
|
2021-12-20 18:40:02 +01:00
|
|
|
</Link>
|
2022-12-04 15:04:56 +01:00
|
|
|
{hasChildren && <Chevron />}
|
2021-12-11 18:19:20 +01:00
|
|
|
</summary>
|
2021-12-22 17:06:50 +01:00
|
|
|
{hasChildren && <SubLevel nodes={current} active={active} />}
|
2021-12-11 18:19:20 +01:00
|
|
|
</details>
|
|
|
|
)
|
|
|
|
|
2022-12-04 15:04:56 +01:00
|
|
|
const Navigation = ({ app, active, className = '' }) => {
|
2021-12-19 18:37:08 +01:00
|
|
|
if (!app.navigation) return null
|
2021-12-12 18:58:24 +01:00
|
|
|
const output = []
|
2022-12-04 15:04:56 +01:00
|
|
|
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={keepClosed.indexOf(page.__slug) === -1}
|
|
|
|
nav={app.navigation}
|
|
|
|
current={order(app.navigation[page.__slug])}
|
|
|
|
active={active}
|
|
|
|
/>
|
|
|
|
)
|
2021-12-12 18:58:24 +01:00
|
|
|
|
2022-05-11 16:29:46 +02:00
|
|
|
return <div className={`pb-20 ${className}`}>{output}</div>
|
|
|
|
}
|
|
|
|
|
2022-05-12 10:27:42 +02:00
|
|
|
export const Icons = ({
|
2022-12-04 15:04:56 +01:00
|
|
|
app,
|
|
|
|
active,
|
|
|
|
ulClasses = '',
|
|
|
|
liClasses = '',
|
|
|
|
linkClasses = `grow text-lg lg:text-xl py-1 text-base-content sm:text-base-content
|
2022-05-12 10:27:42 +02:00
|
|
|
hover:text-secondary sm:hover:text-secondary hover:cursor-pointer
|
2022-06-06 14:06:49 -05:00
|
|
|
flex flex-col items-center`,
|
2022-12-04 15:04:56 +01:00
|
|
|
linkStyle = {},
|
2022-05-12 10:27:42 +02:00
|
|
|
}) => {
|
2022-05-11 16:29:46 +02:00
|
|
|
if (!app.navigation) return null
|
|
|
|
const output = []
|
|
|
|
for (const page of order(app.navigation)) {
|
|
|
|
output.push(
|
2022-05-12 10:27:42 +02:00
|
|
|
<li key={page.__slug} className={liClasses}>
|
2022-12-04 15:04:56 +01:00
|
|
|
<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>
|
2022-05-11 16:29:46 +02:00
|
|
|
</Link>
|
|
|
|
</li>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-05-12 10:27:42 +02:00
|
|
|
return <ul className={ulClasses}>{output}</ul>
|
2021-12-12 18:58:24 +01:00
|
|
|
}
|
|
|
|
|
2022-12-04 15:04:56 +01:00
|
|
|
const PrimaryMenu = ({ app, active, before = [], after = [] }) => (
|
2022-05-11 16:29:46 +02:00
|
|
|
<nav className="mb-12">
|
2022-05-14 19:48:04 +02:00
|
|
|
{before}
|
2022-12-04 15:04:56 +01:00
|
|
|
<Icons app={app} ulClasses="hidden md:block lg:hidden flex flex-col items-center" />
|
|
|
|
<Navigation app={app} active={active} className="md:hidden lg:block" />
|
2022-05-14 19:48:04 +02:00
|
|
|
{after}
|
2021-12-28 16:29:06 +01:00
|
|
|
</nav>
|
|
|
|
)
|
2021-12-11 14:04:05 +01:00
|
|
|
|
|
|
|
export default PrimaryMenu
|