import { siteConfig } from 'site/site.config.mjs'
import { useContext } from 'react'
import { NavigationContext } from 'shared/context/navigation-context.mjs'
import { pageHasChildren, isSlugPart } from 'shared/utils.mjs'
import get from 'lodash.get'
import { HomeIcon, RightIcon, BulletIcon } from 'shared/components/icons.mjs'
import { Link, PageLink } from 'shared/components/link.mjs'
import orderBy from 'lodash.orderby'
import { icons } from 'shared/components/navigation/primary.mjs'
import { useTranslation } from 'next-i18next'
export const ns = ['sections']
/*
* This returns only those children that are expected to show up
* in the side navigation. Specifically:
* - Key length needs to be longer than 1
* - Child pages cannot have m or h set (main section or hidden)
* - Title may not be 'spacer' (header spacer)
*
* It also takes care of ordering them, and returns an array
*
* @params tree {object} - A navigation object as returned by useNavigation => siteNav
*/
const onlyValidChildren = (tree) =>
orderBy(tree, ['o', 't'], ['asc', 'asc']).filter(
(entry) => typeof entry === 'object' && entry.t !== 'spacer' && !entry.m && !entry._ && !entry.h
)
/*
* This returns only those children that are main sections. Specifically:
* - Key length needs to be longer than 1
* - Child pages cannot have m set (main section)
* - Title may not be 'spacer' (header spacer)
*
* It also takes care of ordering them, and returns an array
*
* @params tree {object} - A navigation object as returned by useNavigation => siteNav
*/
const onlyMainSections = (tree) =>
orderBy(tree, ['o', 't'], ['asc', 'asc']).filter((entry) => entry.m)
const SectionLink = ({ skey, tree, slug }) =>
tree[skey]._ ? null : tree[skey].s === slug ? ( // Underscore means always hide
<>
{tree[skey].t}
{pageHasChildren(tree[skey]) && }
>
) : isSlugPart(tree[skey].s, slug) ? (
<>
{tree[skey].t}
{pageHasChildren(tree[skey]) && }
>
) : (
{tree[skey].t}
)
/*
* A React component to render a section of the navigation
*
* @param t {string} - The section title
* @param s {string} - The section slug
* @param tree {object} - The object describing any futher child pages
* @param slug {string} - The slug of the currently active/viewed page
*/
const Section = ({
tree, // Object with the navigation
slug, // Slug of the current page (used to make links active)
}) => (
)
/*
* A React component to render a main link navigation
*
* @param t {string} - The section title
* @param s {string} - The section slug
*/
const MainLink = ({
t, // The link title/text
s, // The link slug
slug, // The current page slug
}) => {
const classes =
'' +
'break-all py-2 px-2 block w-full font-bold text-lg ' +
'flex flex-row items-start gap-0.5 lg:gap-1 border-l-2'
return s === slug ? (
{t}
) : (
{t}
)
}
/*
* A React component to render breadcrumbs to the current page
*
* @param lead {string} - A lead to display before the cumbs (eg: You are here)
*/
export const Breadcrumbs = ({ lead = false }) => {
// Grab siteNav and slug from the navigation context
const { siteNav, slug } = useContext(NavigationContext)
const { t } = useTranslation(['common'])
if (slug === false) {
console.log('No slug passed to Breadcrumbs')
return null
}
// Start with the home crumb
const crumbs = []
// Do we need a lead?
if (lead)
crumbs.push(
{t('youAreHere')}:
)
crumbs.push(
)
// Home page?
if (slug === '') return
{crumbs}
// Then split the slug and add a crumb for each
const chunks = slug.split('/')
for (let i = 1; i <= chunks.length; i++) {
const page = get(siteNav, chunks.slice(0, i))
if (page) {
crumbs.push(
,
i === chunks.length ? (
{page.t}
) : (
)
)
}
}
return
{crumbs}
}
/*
* A React component to render sidebar navigation based on the siteNav object and current slug
*
* The main sections are determined in the navigation prebuild code.
* We always display the navigation as:
* - Always show all top-level entries
* - Always show all direct children of all top-level entries (this allows for better discoverability)
* - If we're deeper down, only expand the active page
*/
export const NavLinks = () => {
// Grab siteNav and slug from the navigation context
const { siteNav, slug } = useContext(NavigationContext)
let subtree = siteNav
/*
* FreeSewing.org has a lot of content, especially the design docs get nested rather deep
* So we trim the navigation tree so that the designs content is not overwhelming
*/
if (siteConfig.tld === 'org') {
const chunks = slug.split('/')
if (chunks[0] === 'docs') {
if (chunks.length > 3) {
if (chunks[1] === 'designs') subtree = siteNav.docs.designs[chunks[2]]
}
// If nothing matched, restrict it to the docs root
if (subtree.blog) subtree = siteNav.docs
}
}
return (
{onlyValidChildren(subtree).map((page, i) => (
{pageHasChildren(page) && !page.n && }
))}
)
}
/*
* A React component to render sidebar navigation for the main sections
*/
export const MainSections = () => {
// Grab siteNav and slug from the navigation context
const { siteNav, slug } = useContext(NavigationContext)
const output = []
for (const page of onlyMainSections(siteNav)) {
const act = isSlugPart(page.s, slug)
const txt = (
<>
{icons[page.s] ? icons[page.s]('w-6 h-6') : }
{page.t}
>
)
const item = (