UNPKG

@nuxt/content

Version:

Write your content inside your Nuxt app

129 lines (128 loc) 4.26 kB
import { pascalCase } from "scule"; import { pick } from "./utils.js"; export async function generateNavigationTree(queryBuilder, extraFields = []) { const params = queryBuilder.__params; if (!params?.orderBy?.length) { queryBuilder = queryBuilder.order("stem", "ASC"); } const collecitonItems = await queryBuilder.orWhere( (group) => group.where("navigation", "<>", "false").where("navigation", "IS NULL") ).select("navigation", "stem", "path", "title", "meta", ...extraFields || []).all(); const { contents, configs } = collecitonItems.reduce((acc, c) => { if (String(c.stem).split("/").pop() === ".navigation") { c.title = c.title?.toLowerCase() === "navigation" ? "" : c.title; const key = c.path.split("/").slice(0, -1).join("/") || "/"; acc.configs[key] = { ...c, ...c.body }; } else { acc.contents.push(c); } return acc; }, { configs: {}, contents: [] }); const pickConfigNavigationFields = (content) => ({ ...pick(["title", ...extraFields])(content), ...content.meta, ...isObject(content?.navigation) ? content.navigation : {} }); const pickNavigationFields = (content) => ({ ...pick(["title", ...extraFields])(content), ...isObject(content?.navigation) ? content.navigation : {} }); const nav = contents.reduce((nav2, content) => { const parts = content.path.substring(1).split("/"); const idParts = content.stem.split("/"); const isIndex = !!idParts[idParts.length - 1]?.match(/([1-9]\d*\.)?index/g); const getNavItem = (content2) => ({ title: content2.title, path: content2.path, stem: content2.stem, children: [], ...pickNavigationFields(content2) }); const navItem = getNavItem(content); if (isIndex) { const dirConfig = configs[navItem.path]; if (typeof dirConfig?.navigation !== "undefined" && dirConfig?.navigation === false) { return nav2; } if (content.path !== "/") { const indexItem = getNavItem(content); navItem.children.push(indexItem); } if (dirConfig) { Object.assign( navItem, pickConfigNavigationFields(dirConfig) ); } } if (parts.length === 1) { const existed2 = nav2.find((item) => item.path === navItem.path && item.page === false); if (isIndex && existed2) { Object.assign(existed2, { page: void 0, children: [ ...navItem.children || [], ...existed2.children || [] ] }); } else { nav2.push(navItem); } return nav2; } const siblings = parts.slice(0, -1).reduce((nodes, part, i) => { const currentPathPart = "/" + parts.slice(0, i + 1).join("/"); const conf = configs[currentPathPart]; if (typeof conf?.navigation !== "undefined" && conf.navigation === false) { return []; } let parent = nodes.find((n) => n.path === currentPathPart); if (!parent) { const navigationConfig = conf ? pickConfigNavigationFields(conf) : {}; parent = { ...navigationConfig, title: navigationConfig.title || generateTitle(part), path: currentPathPart, stem: idParts.slice(0, i + 1).join("/"), children: [], page: false }; nodes.push(parent); } return parent.children; }, nav2); const existed = siblings.find((item) => item.path === navItem.path && item.page === false); if (existed) { Object.assign(existed, { ...navItem, page: void 0, children: [ ...navItem.children || [], ...existed.children || [] ] }); } else { siblings.push(navItem); } return nav2; }, []); return sortAndClear(nav); } function sortAndClear(nav) { const sorted = nav; for (const item of sorted) { if (item.children?.length) { sortAndClear(item.children); } else { delete item.children; } } return nav; } function isObject(obj) { return obj !== null && Object.prototype.toString.call(obj) === "[object Object]"; } export const generateTitle = (path) => path.split(/[\s-]/g).map(pascalCase).join(" ");