From 244f4524c48e54a205315d25ea9b39d649ef297e Mon Sep 17 00:00:00 2001 From: Joost De Cock Date: Sun, 26 Mar 2023 06:50:59 +0200 Subject: [PATCH] wip(dev): Refactoring navigation --- sites/dev/components/feeds.mjs | 6 ++ sites/dev/components/layouts/bare.mjs | 17 ++-- sites/dev/components/layouts/docs.mjs | 52 ++++------- sites/dev/components/navigation/aside.mjs | 18 ++-- sites/dev/components/navigation/primary.mjs | 94 +++++++++----------- sites/dev/components/wrappers/layout.mjs | 13 --- sites/dev/components/wrappers/page.mjs | 71 --------------- sites/dev/hooks/use-bugsnag.mjs | 33 +++++++ sites/dev/lib/load-navigation.mjs | 38 ++++++++ sites/dev/pages/404.mjs | 4 +- sites/dev/pages/[...mdxslug].mjs | 12 ++- sites/dev/pages/contact.mjs | 4 +- sites/dev/pages/index.mjs | 4 +- sites/shared/components/breadcrumbs.mjs | 44 ++++------ sites/shared/components/mdx/prev-next.mjs | 1 + sites/shared/components/wrappers/page.mjs | 97 +++++++++++++++++++++ sites/shared/hooks/use-app.mjs | 35 +++++--- sites/shared/hooks/use-bugsnag.mjs | 36 ++++++++ sites/shared/prebuild/mdx.mjs | 11 +-- sites/shared/prebuild/navigation.mjs | 37 +++++--- 20 files changed, 362 insertions(+), 265 deletions(-) create mode 100644 sites/dev/components/feeds.mjs delete mode 100644 sites/dev/components/wrappers/page.mjs create mode 100644 sites/dev/hooks/use-bugsnag.mjs create mode 100644 sites/dev/lib/load-navigation.mjs create mode 100644 sites/shared/components/wrappers/page.mjs create mode 100644 sites/shared/hooks/use-bugsnag.mjs diff --git a/sites/dev/components/feeds.mjs b/sites/dev/components/feeds.mjs new file mode 100644 index 00000000000..37d8fbe6ef7 --- /dev/null +++ b/sites/dev/components/feeds.mjs @@ -0,0 +1,6 @@ +/* + * Placeholder feeds component that does nothing + * but allows us to re-use code that expects this + * to be here + */ +export const Feeds = () => null diff --git a/sites/dev/components/layouts/bare.mjs b/sites/dev/components/layouts/bare.mjs index 9ce19296d4d..55d7c918a88 100644 --- a/sites/dev/components/layouts/bare.mjs +++ b/sites/dev/components/layouts/bare.mjs @@ -1,14 +1,11 @@ import { useRouter } from 'next/router' import { AsideNavigation } from 'shared/components/navigation/aside.mjs' -export const BareLayout = ({ app, children = [] }) => { - const router = useRouter() - const slug = router.asPath.slice(1) +export const ns = [] - return ( - <> - - {children} - - ) -} +export const BareLayout = ({ app, children = [] }) => ( + <> + + {children} + +) diff --git a/sites/dev/components/layouts/docs.mjs b/sites/dev/components/layouts/docs.mjs index 0eed64fd8bd..a51eecff970 100644 --- a/sites/dev/components/layouts/docs.mjs +++ b/sites/dev/components/layouts/docs.mjs @@ -5,44 +5,22 @@ import Link from 'next/link' import { AsideNavigation } from 'site/components/navigation/aside.mjs' import { ThemePicker } from 'shared/components/theme-picker/index.mjs' import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs' -import { getCrumbs } from 'shared/utils.mjs' import { HomeIcon } from 'shared/components/icons.mjs' import { useState, useEffect } from 'react' -export const DocsLayout = ({ app, title = false, crumbs = false, children = [] }) => { - const router = useRouter() - const [slug, setSlug] = useState('') - const [breadcrumbs, setBreadcrumbs] = useState(crumbs) +export const ns = [] - useEffect(() => { - const newSlug = router.asPath.slice(1) - setSlug(newSlug) - if (!breadcrumbs) setBreadcrumbs(getCrumbs(app, newSlug, title)) - }, [router.asPath, breadcrumbs, app, title]) - - return ( -
- - - - - -
, - ]} - /> -
- {title && ( -
- -

{title}

-
- )} - {children} -
- - ) -} +export const DocsLayout = ({ app, children = [], title }) => ( +
+ +
+ {title && ( +
+ +

{title}

+
+ )} + {children} +
+
+) diff --git a/sites/dev/components/navigation/aside.mjs b/sites/dev/components/navigation/aside.mjs index a10a59d9580..a282c7b084c 100644 --- a/sites/dev/components/navigation/aside.mjs +++ b/sites/dev/components/navigation/aside.mjs @@ -1,26 +1,26 @@ import { MainSections, ActiveSection } from './primary.mjs' +import Link from 'next/link' -export const AsideNavigation = ({ app, slug, mobileOnly = false, before = [], after = [] }) => ( +export const AsideNavigation = ({ app, mobileOnly = false, before = [], after = [] }) => ( ) diff --git a/sites/dev/components/navigation/primary.mjs b/sites/dev/components/navigation/primary.mjs index a528d68eda1..5605405db33 100644 --- a/sites/dev/components/navigation/primary.mjs +++ b/sites/dev/components/navigation/primary.mjs @@ -1,6 +1,7 @@ import Link from 'next/link' import orderBy from 'lodash.orderby' import { TutorialIcon, GuideIcon, HelpIcon, DocsIcon } from 'shared/components/icons.mjs' +import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs' // List of icons matched to top-level slug const icons = { @@ -11,7 +12,7 @@ const icons = { } /* helper method to order nav entries */ -const order = (obj) => orderBy(obj, ['__order', '__title'], ['asc', 'asc']) +const order = (obj) => orderBy(obj, ['o', 't'], ['asc', 'asc']) // Component for the collapse toggle // Exported for re-use @@ -55,12 +56,12 @@ const isActive = (slug, active) => { } // Component that renders a sublevel of navigation -const SubLevel = ({ nodes = {}, active }) => ( +const SubLevel = ({ nodes = {}, active = '' }) => (
    {currentChildren(nodes).map((child) => Object.keys(child).length > 4 ? ( -
  • -
    +
  • +
    ( `} > ( hover:border-secondary sm:hover:border-secondary ${ - child.__slug === active + child.s === active ? 'text-secondary border-secondary sm:text-secondary sm:border-secondary' : 'text-base-content sm:text-base-content' } @@ -92,17 +93,15 @@ const SubLevel = ({ nodes = {}, active }) => ( className={` text-3xl mr-2 inline-block p-0 leading-3 ${ - child.__slug === active + child.s === active ? 'text-secondary sm:text-secondary translate-y-1' : 'translate-y-3' } `} > - {child.__slug === active ? <>• : <>°} - - - {child.__linktitle || child.__title} + {child.s === active ? <>• : <>°} + {child.t} @@ -111,10 +110,10 @@ const SubLevel = ({ nodes = {}, active }) => (
  • ) : ( -
  • +
  • ( hover:border-secondary sm:hover:border-secondary ${ - child.__slug === active + child.s === active ? 'text-secondary border-secondary sm:text-secondary sm:border-secondary' : 'text-base-content sm:text-base-content' }`} @@ -133,17 +132,15 @@ const SubLevel = ({ nodes = {}, active }) => ( className={` text-3xl mr-2 inline-block p-0 leading-3 ${ - child.__slug === active + child.s === active ? 'text-secondary sm:text-secondary translate-y-1' : 'translate-y-3' } `} > - {child.__slug === active ? <>• : <>°} - - - {child.__linktitle || child.__title} + {child.s === active ? <>• : <>°} + {child.t}
  • @@ -164,15 +161,10 @@ export const Icons = ({ const output = [] for (const page of order(app.navigation)) { output.push( -
  • - - {icons[page.__slug] ? icons[page.__slug]('w-14 h-14') : } - {page.__title} +
  • + + {icons[page.s] ? icons[page.s]('w-14 h-14') : } + {page.t}
  • ) @@ -181,24 +173,20 @@ export const Icons = ({ return
      {output}
    } -export const MainSections = ({ app, active }) => { - if (!app.navigation) return null +export const MainSections = ({ app }) => { + if (!app.state.sections) return null const output = [] - for (const page of order(app.navigation)) { - const act = isActive(page.__slug, active) + for (const page of app.state.sections) { + const act = isActive(page.s, app.state.slug) const txt = ( <> - {icons[page.__slug] ? ( - icons[page.__slug](`w-8 h-8 ${act ? 'text-accent' : ''}`) - ) : ( - - )} - {page.__title} + {icons[page.s] ? icons[page.s](`w-8 h-8 ${act ? 'text-accent' : ''}`) : } + {page.t} ) const item = ( -
  • +
  • {act ? ( { p-2 rounded bg-base-200 `} - title={page.__title} + title={page.t} > {txt} ) : ( {txt} @@ -233,13 +221,15 @@ export const MainSections = ({ app, active }) => { return
      {output}
    } -export const ActiveSection = ({ app, active }) => ( -
    - +export const ActiveSection = ({ app }) => ( +
    + {app.state.crumbs ? ( +
    + +
    + ) : null} +
    + +
    ) diff --git a/sites/dev/components/wrappers/layout.mjs b/sites/dev/components/wrappers/layout.mjs index a0098bddb71..69d55c16e4b 100644 --- a/sites/dev/components/wrappers/layout.mjs +++ b/sites/dev/components/wrappers/layout.mjs @@ -1,22 +1,9 @@ -import { useRouter } from 'next/router' import Head from 'next/head' import { Header } from 'site/components/header.mjs' import { Footer } from 'site/components/footer.mjs' import { Search } from 'site/components/search.mjs' export const LayoutWrapper = ({ app, children = [], search, setSearch, noSearch = false }) => { - const startNavigation = () => { - app.startLoading() - // Force close of menu on mobile if it is open - if (app.primaryNavigation) app.setPrimaryNavigation(false) - // Force close of search modal if it is open - if (search) setSearch(false) - } - - const router = useRouter() - router.events?.on('routeChangeStart', startNavigation) - router.events?.on('routeChangeComplete', () => app.stopLoading()) - return (
    { - const swipeHandlers = useSwipeable({ - onSwipedLeft: () => (app.primaryMenu ? app.setPrimaryMenu(false) : null), - onSwipedRight: () => (app.primaryMenu ? null : app.setPrimaryMenu(true)), - trackMouse: true, - }) - - const router = useRouter() - const slug = router.asPath.slice(1) - - useEffect(() => app.setSlug(slug), [slug, app]) - - // Trigger search with Ctrl+k - useHotkeys('ctrl+k', (evt) => { - evt.preventDefault() - setSearch(true) - }) - - const [search, setSearch] = useState(false) - - const childProps = { - app: app, - title: title, - crumbs: crumbs, - search, - setSearch, - toggleSearch: () => setSearch(!search), - noSearch: noSearch, - } - - const Layout = layout - - return ( -
    - - - {title} - FreeSewing.dev - - - {Layout ? {children} : children} - - {app.popup && app.setPopup(false)}>{app.popup}} - {app.loading && } -
    - ) -} diff --git a/sites/dev/hooks/use-bugsnag.mjs b/sites/dev/hooks/use-bugsnag.mjs new file mode 100644 index 00000000000..5bcb2993183 --- /dev/null +++ b/sites/dev/hooks/use-bugsnag.mjs @@ -0,0 +1,33 @@ +/* + * Dumb method to generate a unique (enough) ID for submissions to bugsnag + */ +function createErrorId() { + let result = '' + const characters = 'abcdefghijklmnopqrstuvwxyz0123456789' + const charactersLength = characters.length + for (let s = 0; s < 3; s++) { + for (let i = 0; i < 4; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)) + } + if (s < 2) result += '-' + } + + return result +} + +/* + * The hook + */ +export function useBugsnag(bugsnag) { + const reportError = (err) => { + const id = createErrorId() + bugsnag.notify(err, (evt) => { + evt.setUser(account.username ? account.username : '__visitor') + evt.context = id + }) + + return id + } + + return reportError +} diff --git a/sites/dev/lib/load-navigation.mjs b/sites/dev/lib/load-navigation.mjs new file mode 100644 index 00000000000..61b6dbe4c88 --- /dev/null +++ b/sites/dev/lib/load-navigation.mjs @@ -0,0 +1,38 @@ +import get from 'lodash.get' +import { prebuildNavigation as pbn } from 'site/prebuild/navigation.mjs' +import orderBy from 'lodash.orderby' + +const createCrumbs = (saa) => + saa.map((crumb, i) => { + const entry = get(pbn.en, saa.slice(0, i + 1)) + const val = { t: entry.t, s: entry.s } + if (entry.o) val.o = entry.o + + return val + }) + +const createSections = () => { + const sections = {} + for (const slug of Object.keys(pbn.en)) { + const entry = pbn.en[slug] + const val = { t: entry.t, s: entry.s } + if (entry.o) val.o = entry.o + sections[slug] = val + } + + return orderBy(sections, 'o') +} + +export const loadNavigation = (saa = []) => { + // Creat crumbs array + const crumbs = createCrumbs(saa) + + return { + saa, + slug: saa.join('/'), + crumbs, + sections: createSections(), + nav: saa.length > 1 ? get(pbn.en, saa[0]) : pbn.en[saa[0]], + title: crumbs.slice(-1)[0].t, + } +} diff --git a/sites/dev/pages/404.mjs b/sites/dev/pages/404.mjs index 7f6cc3ab5e2..db0cfcb3069 100644 --- a/sites/dev/pages/404.mjs +++ b/sites/dev/pages/404.mjs @@ -1,8 +1,8 @@ // Hooks -import { useApp } from 'site/hooks/useApp.mjs' +import { useApp } from 'shared/hooks/use-app.mjs' // Components import Head from 'next/head' -import { PageWrapper } from 'site/components/wrappers/page.mjs' +import { PageWrapper } from 'shared/components/wrappers/page.mjs' import { BareLayout } from 'site/components/layouts/bare.mjs' import { Robot } from 'shared/components/robot/index.mjs' import { Popout } from 'shared/components/popout.mjs' diff --git a/sites/dev/pages/[...mdxslug].mjs b/sites/dev/pages/[...mdxslug].mjs index e7c836c374d..1d968ac6002 100644 --- a/sites/dev/pages/[...mdxslug].mjs +++ b/sites/dev/pages/[...mdxslug].mjs @@ -1,12 +1,12 @@ // Hooks -import { useApp } from 'site/hooks/useApp.mjs' +import { useApp } from 'shared/hooks/use-app.mjs' // Dependencies import mdxMeta from 'site/prebuild/mdx.en.js' import { mdxLoader } from 'shared/mdx/loader.mjs' import { serverSideTranslations } from 'next-i18next/serverSideTranslations' // Components import Head from 'next/head' -import { PageWrapper } from 'site/components/wrappers/page.mjs' +import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs' import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs' import { TocWrapper } from 'shared/components/wrappers/toc.mjs' import { HelpUs } from 'site/components/help-us.mjs' @@ -14,7 +14,7 @@ import { jargon } from 'site/jargon.mjs' const MdxPage = (props) => { // This hook is used for shared code and global state - const app = useApp() + const app = useApp(props) /* * Each page should be wrapped in the Page wrapper component @@ -26,7 +26,7 @@ const MdxPage = (props) => { * active state */ return ( - + @@ -83,9 +83,7 @@ export async function getStaticProps({ params }) { toc, intro: intro.join(' '), page: { - slug: params.mdxslug.join('/'), - path: '/' + params.mdxslug.join('/'), - slugArray: params.mdxslug, + saa: params.mdxslug, // slug as array (saa) ...mdxMeta[params.mdxslug.join('/')], }, params, diff --git a/sites/dev/pages/contact.mjs b/sites/dev/pages/contact.mjs index 487afc19c79..4fc385e9dfc 100644 --- a/sites/dev/pages/contact.mjs +++ b/sites/dev/pages/contact.mjs @@ -1,10 +1,10 @@ // Hooks -import { useApp } from 'site/hooks/useApp.mjs' +import { useApp } from 'shared/hooks/use-app.mjs' // Dependencies import { serverSideTranslations } from 'next-i18next/serverSideTranslations' // Components import Head from 'next/head' -import { PageWrapper } from 'site/components/wrappers/page.mjs' +import { PageWrapper } from 'shared/components/wrappers/page.mjs' import { Popout } from 'shared/components/popout.mjs' import { WebLink } from 'shared/components/web-link.mjs' diff --git a/sites/dev/pages/index.mjs b/sites/dev/pages/index.mjs index 3a6be7114fc..9526ab7ab57 100644 --- a/sites/dev/pages/index.mjs +++ b/sites/dev/pages/index.mjs @@ -1,10 +1,10 @@ // Hooks -import { useApp } from 'site/hooks/useApp.mjs' +import { useApp } from 'shared/hooks/use-app.mjs' // Dependencies import { serverSideTranslations } from 'next-i18next/serverSideTranslations' // Components import Head from 'next/head' -import { PageWrapper } from 'site/components/wrappers/page.mjs' +import { PageWrapper } from 'shared/components/wrappers/page.mjs' import { BareLayout } from 'site/components/layouts/bare.mjs' import { Icons } from 'shared/components/navigation/primary.mjs' import { Highlight } from 'shared/components/mdx/highlight.mjs' diff --git a/sites/shared/components/breadcrumbs.mjs b/sites/shared/components/breadcrumbs.mjs index 1248dbdc0a1..9f2adec1abf 100644 --- a/sites/shared/components/breadcrumbs.mjs +++ b/sites/shared/components/breadcrumbs.mjs @@ -1,32 +1,22 @@ -import { Fragment } from 'react' +import { HomeIcon } from 'shared/components/icons.mjs' import Link from 'next/link' -import { FreeSewingIcon } from 'shared/components/icons.mjs' -export const Breadcrumbs = ({ crumbs = [] }) => +export const Breadcrumbs = ({ crumbs, title }) => crumbs ? ( -
      -
    • - - - -
    • - {crumbs.map((crumb) => ( - -
    • »
    • -
    • - {crumb[1] ? ( - - {crumb[0]} - - ) : ( - {crumb[0]} - )} +
      +
        +
      • + + + +
      • + {crumbs.map((crumb) => ( +
      • + + {crumb.t} +
      • - - ))} -
      + ))} +
    +
    ) : null diff --git a/sites/shared/components/mdx/prev-next.mjs b/sites/shared/components/mdx/prev-next.mjs index 9e3426f15f8..cf6f810a678 100644 --- a/sites/shared/components/mdx/prev-next.mjs +++ b/sites/shared/components/mdx/prev-next.mjs @@ -96,6 +96,7 @@ const renderNext = (node) => ) export const PrevNext = ({ app }) => { + return

    fixme: prevnext

    return (
    {renderPrevious(previous(app))} diff --git a/sites/shared/components/wrappers/page.mjs b/sites/shared/components/wrappers/page.mjs new file mode 100644 index 00000000000..952b49cf201 --- /dev/null +++ b/sites/shared/components/wrappers/page.mjs @@ -0,0 +1,97 @@ +// Dependencies +import React, { useState, useEffect } from 'react' +import { useSwipeable } from 'react-swipeable' +import { useHotkeys } from 'react-hotkeys-hook' +// Hooks +import { useTheme } from 'shared/hooks/use-theme.mjs' +// Components +import { LayoutWrapper, ns as layoutNs } from 'site/components/wrappers/layout.mjs' +import { DocsLayout } from 'site/components/layouts/docs.mjs' +import { Feeds } from 'site/components/feeds.mjs' + +//export const ns = [...layoutNs] + +/* This component should wrap all page content */ +export const PageWrapper = ({ + noSearch = false, + app = false, + layout = DocsLayout, + footer = true, + children = [], + title = 'FIXME: No title set', +}) => { + /* + * This forces a re-render upon initial bootstrap of the app + * This is needed to avoid hydration errors because theme can't be set reliably in SSR + */ + const [theme, setTheme] = useTheme() + const [currentTheme, setCurrentTheme] = useState() + useEffect(() => setCurrentTheme(theme), [currentTheme, theme]) + + /* + * Swipe handling for the entire site + */ + const swipeHandlers = useSwipeable({ + onSwipedLeft: () => (app.primaryMenu ? app.setPrimaryMenu(false) : null), + onSwipedRight: () => (app.primaryMenu ? null : app.setPrimaryMenu(true)), + trackMouse: true, + }) + + /* + * Hotkeys (keyboard actions) + */ + // Trigger search with / + useHotkeys('/', (evt) => { + evt.preventDefault() + setSearch(true) + }) + + // Always close modal when Escape key is hit + useHotkeys('esc', (evt) => { + evt.preventDefault() + app.setModal(false) + }) + + // Search state + const [search, setSearch] = useState(false) + + // Helper object to pass props down (keeps things DRY) + const childProps = { + app: app, + footer, + search, + setSearch, + toggleSearch: () => setSearch(!search), + noSearch: noSearch, + title, + } + + // Make layout prop into a (uppercase) component + const Layout = layout + + // Return wrapper + return ( +
    + + + {Layout ? {children} : children} + + {app.modal ? ( +
    app.setModal(false)} + > + {app.modal} +
    + ) : null} +
    + ) +} diff --git a/sites/shared/hooks/use-app.mjs b/sites/shared/hooks/use-app.mjs index 92605aee243..850cb41a918 100644 --- a/sites/shared/hooks/use-app.mjs +++ b/sites/shared/hooks/use-app.mjs @@ -1,28 +1,36 @@ +import { loadNavigation } from 'site/lib/load-navigation.mjs' // Hooks -import { useState } from 'react' -import { useBugsnag } from 'site/hooks/use-bugsnag.mjs' -import { useRouter } from 'next/router' +import { useState, useEffect } from 'react' +import { useBugsnag } from 'shared/hooks/use-bugsnag.mjs' // Dependencies +import get from 'lodash.get' import set from 'lodash.set' import unset from 'lodash.unset' const defaultState = { loading: false, modal: null, + menu: { + main: null, + }, } /* * The useApp hook */ -export function useApp({ bugsnag }) { - const router = useRouter() - const reportError = useBugsnag ? useBugsnag(bugsnag) : () => false +export function useApp(props = {}) { + const { bugsnag = false, page = {}, loadState = {} } = props + const { saa = [] } = page + + const reportError = useBugsnag(props?.bugsnag) // React state - const [state, setState] = useState({ - ...defaultState, - slug: useRouter().asPath.slice(1), - }) + const [state, setState] = useState(() => ({ ...defaultState, ...loadState })) + + useEffect(() => { + // Force update of navigation info (nav, title, crumbs) on each page change + if (saa.length > 0) setState({ ...state, ...loadNavigation(saa) }) + }, [saa, state.slug, state.title]) /* * Helper methods for partial state updates @@ -33,7 +41,9 @@ export function useApp({ bugsnag }) { /* * Helper methods for specific state updates */ - const clearModal = () => updateState('modal', null) + const closeModal = () => updateState('modal', null) + const closeMenu = (name) => + get(state, `menu.${name}`, false) ? updateState(`menu.${name}`, false) : null const startLoading = () => updateState('loading', true) const stopLoading = () => updateState('loading', false) @@ -45,7 +55,8 @@ export function useApp({ bugsnag }) { unsetState, // Helper methods - clearModal, + closeModal, + closeMenu, startLoading, stopLoading, diff --git a/sites/shared/hooks/use-bugsnag.mjs b/sites/shared/hooks/use-bugsnag.mjs new file mode 100644 index 00000000000..f000d407ac7 --- /dev/null +++ b/sites/shared/hooks/use-bugsnag.mjs @@ -0,0 +1,36 @@ +/* + * Dumb method to generate a unique (enough) ID for submissions to bugsnag + */ +function createErrorId() { + let result = '' + const characters = 'abcdefghijklmnopqrstuvwxyz0123456789' + const charactersLength = characters.length + for (let s = 0; s < 3; s++) { + for (let i = 0; i < 4; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)) + } + if (s < 2) result += '-' + } + + return result +} + +/* + * The hook + */ +export function useBugsnag(bugsnag) { + // If we don't use bugsnag, return a placeholder method + if (!bugsnag) return () => false + + const reportError = (err) => { + const id = createErrorId() + bugsnag.notify(err, (evt) => { + evt.setUser(account.username ? account.username : '__visitor') + evt.context = id + }) + + return id + } + + return reportError +} diff --git a/sites/shared/prebuild/mdx.mjs b/sites/shared/prebuild/mdx.mjs index 9b00167e045..694347cd817 100644 --- a/sites/shared/prebuild/mdx.mjs +++ b/sites/shared/prebuild/mdx.mjs @@ -122,11 +122,8 @@ export const prebuildMdx = async (site) => { if (slug) { const meta = await mdxMetaInfo(file) if (meta.data?.title) { - pages[lang][slug] = { - title: meta.data.title, - slug, - order: meta.data.order ? `${meta.data.order}${meta.data.title}` : meta.data.title, - } + pages[lang][slug] = { t: meta.data.title } + if (meta.data.order) pages[lang][slug].o = `${meta.data.order}${meta.data.title}` } else { if (pages.en[slug]) { console.log(`⚠️l Falling back to EN metadata for ${slug}`) @@ -146,14 +143,14 @@ export const prebuildMdx = async (site) => { fs.writeFileSync( path.resolve('..', site, 'prebuild', `mdx.${lang}.js`), - `export default ${JSON.stringify(pages[lang], null, 2)}` + `export default ${JSON.stringify(pages[lang])}` ) } // Write list of all MDX paths (in one language) fs.writeFileSync( path.resolve('..', site, 'prebuild', `mdx.paths.mjs`), - `export const mdxPaths = ${JSON.stringify(Object.keys(pages.en), null, 2)}` + `export const mdxPaths = ${JSON.stringify(Object.keys(pages.en))}` ) return pages diff --git a/sites/shared/prebuild/navigation.mjs b/sites/shared/prebuild/navigation.mjs index a3077521e1c..a030c9ccbf6 100644 --- a/sites/shared/prebuild/navigation.mjs +++ b/sites/shared/prebuild/navigation.mjs @@ -9,6 +9,15 @@ const future = new Date('10-12-2026').getTime() * Main method that does what needs doing */ export const prebuildNavigation = (mdxPages, strapiPosts, site) => { + /* + * Since this is written to disk and loaded as JSON, we minimize + * the data to load by using the following 1-character keys: + * + * t: title + * l: link title (shorter version of the title, optional + * o: order, optional + * s: slug without leading or trailing slash (/) + */ const nav = {} for (const lang in mdxPages) { nav[lang] = {} @@ -17,29 +26,29 @@ export const prebuildNavigation = (mdxPages, strapiPosts, site) => { for (const slug of Object.keys(mdxPages[lang]).sort()) { const page = mdxPages[lang][slug] const chunks = slug.split('/') - set(nav, [lang, ...chunks], { - __title: page.title, - __linktitle: page.linktitle || page.title, - __slug: slug, - __order: page.order, - }) + const val = { + t: page.t, + s: slug, + } + if (page.o) val._o = page.o + set(nav, [lang, ...chunks], val) } // Handle strapi content for (const type in strapiPosts) { set(nav, [lang, type], { - __title: type, - __linktitle: type, - __slug: type, - __order: type, + t: type, + l: type, + s: type, + o: type, }) for (const [slug, page] of Object.entries(strapiPosts[type][lang])) { const chunks = slug.split('/') set(nav, [lang, type, ...chunks], { - __title: page.title, - __linktitle: page.linktitle, - __slug: type + '/' + slug, - __order: (future - new Date(page.date).getTime()) / 100000, + t: page.title, + l: page.linktitle, + s: type + '/' + slug, + o: (future - new Date(page.date).getTime()) / 100000, }) } }