diff --git a/AWSCLIV2.pkg b/AWSCLIV2.pkg deleted file mode 100644 index cc4804c3e..000000000 Binary files a/AWSCLIV2.pkg and /dev/null differ diff --git a/netlify.toml b/netlify.toml index 36075e6bc..33044d26a 100644 --- a/netlify.toml +++ b/netlify.toml @@ -10,3 +10,7 @@ ORG_NAME = "mongodb" REPO_NAME = "docs-landing" BRANCH_NAME = "master" PARSER_VERSION = "0.18.9" + +# remove when merged +[context.deploy-preview.environment] +GATSBY_USE_UNIFIED_TOC = "true" diff --git a/package-lock.json b/package-lock.json index d1c52a8bc..575c7f27a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,6 +72,7 @@ "html-screen-capture-js": "^1.0.50", "https-browserify": "^1.0.0", "immer": "^9.0.6", + "js-toml": "^1.0.1", "json-schema": "^0.4.0", "lodash": "^4.6.0", "minimist": "^1.2.6", @@ -1834,6 +1835,23 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.26.0", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", + "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/@babel/runtime/node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -1893,6 +1911,40 @@ "partytown": "bin/partytown.cjs" } }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==" + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -13732,6 +13784,19 @@ "node": "*" } }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, "node_modules/chokidar": { "version": "3.5.3", "funding": [ @@ -14350,9 +14415,10 @@ } }, "node_modules/core-js-pure": { - "version": "3.28.0", + "version": "3.39.0", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/core-js-pure/-/core-js-pure-3.39.0.tgz", + "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==", "hasInstallScript": true, - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -22149,6 +22215,15 @@ "version": "4.0.0", "license": "MIT" }, + "node_modules/js-toml": { + "version": "1.0.1", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/js-toml/-/js-toml-1.0.1.tgz", + "integrity": "sha512-rHd/IolpFm2V5BmHCEY8CckHs8NDsYZZ64H5RNgA6Opsr9vX4QyTiQPplgtqg7b3ztqYShZC38nl6CUg7QuhXg==", + "dependencies": { + "chevrotain": "^11.0.3", + "xregexp": "^5.1.1" + } + }, "node_modules/js-yaml": { "version": "3.14.1", "license": "MIT", @@ -22602,6 +22677,11 @@ "version": "4.17.21", "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "license": "MIT" @@ -32114,6 +32194,14 @@ "version": "0.6.1", "license": "MIT" }, + "node_modules/xregexp": { + "version": "5.1.1", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/xregexp/-/xregexp-5.1.1.tgz", + "integrity": "sha512-fKXeVorD+CzWvFs7VBuKTYIW63YD1e1osxwQ8caZ6o1jg6pDAbABDG54LCIq0j5cy7PjRvGIq6sef9DYPXpncg==", + "dependencies": { + "@babel/runtime-corejs3": "^7.16.5" + } + }, "node_modules/xstate": { "version": "4.38.3", "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/xstate/-/xstate-4.38.3.tgz", @@ -33265,6 +33353,22 @@ } } }, + "@babel/runtime-corejs3": { + "version": "7.26.0", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", + "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", + "requires": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + } + } + }, "@babel/template": { "version": "7.25.9", "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@babel/template/-/template-7.25.9.tgz", @@ -33305,6 +33409,40 @@ "@builder.io/partytown": { "version": "0.7.5" }, + "@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "requires": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "requires": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==" + }, + "@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==" + }, + "@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==" + }, "@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -41916,6 +42054,19 @@ "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/charenc/-/charenc-0.0.2.tgz", "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" }, + "chevrotain": { + "version": "11.0.3", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "requires": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, "chokidar": { "version": "3.5.3", "requires": { @@ -42326,7 +42477,9 @@ } }, "core-js-pure": { - "version": "3.28.0" + "version": "3.39.0", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/core-js-pure/-/core-js-pure-3.39.0.tgz", + "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==" }, "core-util-is": { "version": "1.0.3" @@ -47289,6 +47442,15 @@ "js-tokens": { "version": "4.0.0" }, + "js-toml": { + "version": "1.0.1", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/js-toml/-/js-toml-1.0.1.tgz", + "integrity": "sha512-rHd/IolpFm2V5BmHCEY8CckHs8NDsYZZ64H5RNgA6Opsr9vX4QyTiQPplgtqg7b3ztqYShZC38nl6CUg7QuhXg==", + "requires": { + "chevrotain": "^11.0.3", + "xregexp": "^5.1.1" + } + }, "js-yaml": { "version": "3.14.1", "requires": { @@ -47584,6 +47746,11 @@ "lodash": { "version": "4.17.21" }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash.clonedeep": { "version": "4.5.0" }, @@ -53709,6 +53876,14 @@ "xmlserializer": { "version": "0.6.1" }, + "xregexp": { + "version": "5.1.1", + "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/xregexp/-/xregexp-5.1.1.tgz", + "integrity": "sha512-fKXeVorD+CzWvFs7VBuKTYIW63YD1e1osxwQ8caZ6o1jg6pDAbABDG54LCIq0j5cy7PjRvGIq6sef9DYPXpncg==", + "requires": { + "@babel/runtime-corejs3": "^7.16.5" + } + }, "xstate": { "version": "4.38.3", "resolved": "https://artifactory.corp.mongodb.com/artifactory/api/npm/npm/xstate/-/xstate-4.38.3.tgz", diff --git a/package.json b/package.json index 475c5bbba..9e44650c8 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "html-screen-capture-js": "^1.0.50", "https-browserify": "^1.0.0", "immer": "^9.0.6", + "js-toml": "^1.0.1", "json-schema": "^0.4.0", "lodash": "^4.6.0", "minimist": "^1.2.6", diff --git a/plugins/gatsby-source-snooty-prod/gatsby-node.js b/plugins/gatsby-source-snooty-prod/gatsby-node.js index 2c408bfc4..e44490c13 100644 --- a/plugins/gatsby-source-snooty-prod/gatsby-node.js +++ b/plugins/gatsby-source-snooty-prod/gatsby-node.js @@ -1,4 +1,5 @@ const swc = require('@swc/core'); +// const { load } = require('js-toml'); const path = require('path'); const fs = require('fs/promises'); const { transformBreadcrumbs } = require('../../src/utils/setup/transform-breadcrumbs.js'); @@ -21,7 +22,7 @@ const { createOpenAPIChangelogNode } = require('../utils/openapi.js'); const { createProductNodes } = require('../utils/products.js'); const { createDocsetNodes } = require('../utils/docsets.js'); const { createBreadcrumbNodes } = require('../utils/breadcrumbs.js'); - +const { createTocNodes } = require('../utils/unified-toc.js'); const assets = new Map(); const projectComponents = new Set(); @@ -127,6 +128,7 @@ exports.sourceNodes = async ({ actions, createContentDigest, createNodeId, getNo ); process.exit(1); } + const pageIdPrefix = constructPageIdPrefix(siteMetadata); documents.forEach((doc) => { const { page_id, ...rest } = doc; @@ -195,6 +197,9 @@ exports.sourceNodes = async ({ actions, createContentDigest, createNodeId, getNo await createBreadcrumbNodes({ db, createNode, createNodeId, createContentDigest }); + // create TOC nodes + await createTocNodes({ createNode, createNodeId, createContentDigest }); + if (process.env['OFFLINE_DOCS'] !== 'true') { const umbrellaProduct = await db.realmInterface.getMetadata( { @@ -420,5 +425,8 @@ exports.createSchemaCustomization = ({ actions }) => { propertyUrl: String } + type TOC implements Node @dontInfer { + tocTree: JSON! + } `); }; diff --git a/plugins/utils/unified-toc.js b/plugins/utils/unified-toc.js new file mode 100644 index 000000000..45890d1b6 --- /dev/null +++ b/plugins/utils/unified-toc.js @@ -0,0 +1,27 @@ +const { load } = require('js-toml'); +const fs = require('fs/promises'); + +const createTocNodes = async ({ createNode, createNodeId, createContentDigest }) => { + // Get all MongoDB products for the sidenav + + try { + const tomlContents = (await fs.readFile(`${process.cwd()}/toc_data/toc.toml`)).toString(); + const toc = load(tomlContents); + + createNode({ + tocTree: toc, + id: createNodeId('toc'), + internal: { + contentDigest: createContentDigest(toc), + type: 'TOC', + }, + parent: null, + }); + } catch (e) { + console.error('error occurred when reading the toc.toml', e); + } +}; + +module.exports = { + createTocNodes, +}; diff --git a/src/components/Sidenav/styles/sideNavItem.js b/src/components/Sidenav/styles/sideNavItem.js index ee586e679..abd5b032e 100644 --- a/src/components/Sidenav/styles/sideNavItem.js +++ b/src/components/Sidenav/styles/sideNavItem.js @@ -9,24 +9,19 @@ export const sideNavItemBasePadding = css` padding-bottom: ${theme.size.small}; `; -export const sideNavItemTOCStyling = ({ level = 1 }) => css` - padding-bottom: ${theme.size.small}; - padding-left: calc(${theme.size.tiny} + (${level} * ${theme.size.default})); - padding-right: ${theme.size.medium}; - padding-top: ${theme.size.small}; +export const sideNavItemTOCStyling = ({ level }) => css` align-items: flex-start !important; font-size: ${theme.fontSize.small}; text-transform: none; line-height: 20px !important; + padding-left: calc(16px + ${(level - 1) * 25}px); +`; - // overwrite LG link underlines - // @leafygreen-ui/typography v13.0.0 - :hover { - &:after, - span:after { - display: none; - } - } +export const sideNavGroupTOCStyling = ({ level }) => css` + align-items: flex-start !important; + font-size: ${theme.fontSize.small}; + text-transform: none; + line-height: 20px !important; `; export const sideNavItemFontSize = css` diff --git a/src/components/UnifiedSidenav/UnifiedSidenav.js b/src/components/UnifiedSidenav/UnifiedSidenav.js new file mode 100644 index 000000000..3d5f0dca6 --- /dev/null +++ b/src/components/UnifiedSidenav/UnifiedSidenav.js @@ -0,0 +1,193 @@ +import React, { useState } from 'react'; +import styled from '@emotion/styled'; +import { SideNav, SideNavGroup, SideNavItem } from '@leafygreen-ui/side-nav'; +import { css as LeafyCSS, cx } from '@leafygreen-ui/emotion'; + +import Icon from '@leafygreen-ui/icon'; +import { palette } from '@leafygreen-ui/palette'; +import Link from '../Link'; +// import { formatText } from '../../utils/format-text'; + +import { sideNavItemTOCStyling, sideNavGroupTOCStyling } from '../Sidenav/styles/sideNavItem'; +import { useUnifiedToc } from '../../hooks/use-unified-toc'; +import { theme } from '../../theme/docsTheme'; +import { isBrowser } from '../../utils/is-browser'; + +const FormatTitle = styled.div` + scroll-margin-bottom: ${theme.size.xxlarge}; +`; +const overwriteLinkStyle = LeafyCSS` + span { + display: flex; + } +`; + +const chevronStyle = LeafyCSS` + margin-top: 3px; +`; + +const sideNavStyle = LeafyCSS` + padding: 0px; + div > ul { + display: flex; + flex-direction: row; + // width: 400px; + // height: 100vh; + // overflow-y: auto; + // position: fixed; + // left: 0; + // top: 0; + + ul { + display: block; + width: 100%; + + li { + a { + justify-content: space-between !important; + } + } + } + } +`; + +const leftPane = LeafyCSS` + flex: 1; + // padding: 10px; + overflow-y: auto; + background-color: #f8f9fa; + border-right: 3px solid #ddd; +`; + +const rightPane = LeafyCSS` + flex: 2; + // padding: 10px; + overflow-y: auto; +`; + +// we will have to edit this function in the future since if we have double panned side nav in theory two things should be selected at same time +function isSelectedTab(slug) { + if (!isBrowser) return false; + + return window.location.pathname === `${slug}/`; +} + +function CollapsibleNavItem({ items, label, url, level }) { + const [isOpen, setIsOpen] = useState(false); + const chevronType = isOpen ? 'ChevronDown' : 'ChevronRight'; + + const onChevronClick = (event) => { + event.preventDefault(); + setIsOpen(!isOpen); + }; + + return ( + <> + setIsOpen(!isOpen)} + hideExternalIcon={true} + > + {label} + + + {isOpen && items.map((item) => )} + + ); +} + +function UnifiedTocNavItem({ label, group, url, collapsible, items, isTab, level }) { + // these are the tab items that we dont need to show in the second pane but need to go through recursively + if (isTab) { + return ( + <> + {items?.map((tocItem) => ( + + ))} + + ); + } + + // groups are for adding a static header, these can also be collapsible + if (group) { + return ( + + {items?.map((tocItem) => ( + + ))} + + ); + } + + // collapsible is for items that have nested links + if (collapsible) { + return ( + + ); + } + + return ( + + {label} + + ); +} + +function StaticNavItem({ label, group, url, collapsible, items, glyph, isTab, setActiveTab, level = 1 }) { + return ( + } + aria-label={label} + as={Link} + to={url} + className={cx(sideNavItemTOCStyling({ level }))} + onClick={() => setActiveTab(`${url}/`)} + > + {label} + + ); +} + +export function UnifiedSidenav() { + const unifiedTocTree = useUnifiedToc(); + const [activeTab, setActiveTab] = useState(window.location.pathname); + const staticToc = unifiedTocTree.filter((item) => item?.isTab); + + // Hide the Sidenav with css while keeping state as open/not collapsed. + // This prevents LG's SideNav component from being seen in its collapsed state on mobile + return ( + <> + +
+ {staticToc.map((navItems) => { + return ; + })} +
+
+ {unifiedTocTree.map((navItems) => { + if (`${navItems.url}/` === activeTab) { + return ; + } + return null; + })} +
+
+ + ); +} diff --git a/src/hooks/use-unified-toc.js b/src/hooks/use-unified-toc.js new file mode 100644 index 000000000..02a9cc53e --- /dev/null +++ b/src/hooks/use-unified-toc.js @@ -0,0 +1,15 @@ +const { useStaticQuery, graphql } = require('gatsby'); + +export function useUnifiedToc() { + const data = useStaticQuery( + graphql` + query TocTree { + toc { + id + tocTree + } + } + ` + ); + return data.toc.tocTree.toc ?? {}; +} diff --git a/src/layouts/index.js b/src/layouts/index.js index 1e83b5df8..b41fd45ed 100644 --- a/src/layouts/index.js +++ b/src/layouts/index.js @@ -13,6 +13,8 @@ import { theme } from '../theme/docsTheme'; import useSnootyMetadata from '../utils/use-snooty-metadata'; import { useRemoteMetadata } from '../hooks/use-remote-metadata'; import { getAllLocaleCssStrings } from '../utils/locale'; +import { UnifiedSidenav } from '../components/UnifiedSidenav/UnifiedSidenav'; +import { getFeatureFlags } from '../utils/feature-flags'; // TODO: Delete this as a part of the css cleanup // Currently used to preserve behavior and stop legacy css @@ -94,6 +96,7 @@ export const StyledContentContainer = styled('div')` const DefaultLayout = ({ children, data: { page }, pageContext: { slug, repoBranches, template } }) => { const { sidenav } = getTemplate(template); const { chapters, guides, slugToTitle, toctree, eol, project } = useSnootyMetadata(); + const { isUnifiedToc } = getFeatureFlags(); const remoteMetadata = useRemoteMetadata(); const isInPresentationMode = usePresentationMode()?.toLocaleLowerCase() === 'true'; @@ -115,7 +118,9 @@ const DefaultLayout = ({ children, data: { page }, pageContext: { slug, repoBran > {!isInPresentationMode ?
:
} - {sidenav && !isInPresentationMode ? ( + {isUnifiedToc ? ( + + ) : sidenav && !isInPresentationMode ? (