From 04569b699b0365bea9b4c4f03e9862654a827b10 Mon Sep 17 00:00:00 2001 From: Abdul-jailani Date: Thu, 26 Mar 2026 15:12:06 +0530 Subject: [PATCH 1/3] Tried to reduce page size --- gatsby-node.js | 71 ++++++- src/components/LeftNav.jsx | 259 +++++++++++++++-------- src/components/MobileView.jsx | 11 +- src/pages/docs/test-management/index.jsx | 50 ++++- src/templates/page.jsx | 10 +- tailwind.config.js | 4 +- 6 files changed, 292 insertions(+), 113 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 9e834dd..61bb35b 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -9,6 +9,26 @@ const leftNavTitle = require('./src/left-nav-title.json'); const ignorePaths = []; +let builtNavTree = null; + +const NAV_META_KEYS = new Set(['leftNavTitle', 'old', 'overview', 'url', 'title']); + +function extractSubsectionMeta(sectionData) { + const keys = Object.keys(sectionData).filter( + (k) => !NAV_META_KEYS.has(k) + ); + return keys.map((key) => { + const item = sectionData[key]; + const isLeaf = !!item.url && Object.keys(item).filter((k) => !NAV_META_KEYS.has(k)).length === 0; + return { + key, + title: item.leftNavTitle || key.replaceAll('-', ' '), + overviewUrl: item?.overview?.url || (isLeaf ? item.url : null), + isLeaf, + }; + }); +} + exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions; if (node.internal.type === 'MarkdownRemark') { @@ -56,6 +76,9 @@ exports.createPages = async ({ graphql, actions }) => { } } `); + const mainSection = builtNavTree?.['test-management'] ?? null; + const navSubsections = mainSection ? extractSubsectionMeta(mainSection) : []; + result.data.allMarkdownRemark.edges.forEach(({ node }, index) => { if (node.fields.slug.includes('-')) { const underscoreSlug = node.fields.slug.replace(/-/g, '_'); @@ -67,6 +90,14 @@ exports.createPages = async ({ graphql, actions }) => { toPath: node.fields.slug, }); } + + const slugParts = node.fields.slug.split('/').filter(Boolean); + const activeSubSection = slugParts.length >= 3 ? slugParts[2] : null; + const activeNavData = + activeSubSection && mainSection && mainSection[activeSubSection] + ? JSON.stringify(mainSection[activeSubSection]) + : null; + createPage({ path: node.fields.slug, component: path.resolve('./src/templates/page.jsx'), @@ -80,6 +111,9 @@ exports.createPages = async ({ graphql, actions }) => { index === result.data.allMarkdownRemark.edges.length - 1 ? null : result.data.allMarkdownRemark.edges[index + 1].node, + navSubsections, + activeSubSection, + activeNavData, }, }); }); @@ -95,6 +129,22 @@ exports.onPostBuild = () => { } else { console.error('Sitemap.xml not found in src/pages/docs/'); } + + if (builtNavTree?.['test-management']) { + const navDataDir = path.join(__dirname, 'public', 'nav-data'); + if (!fs.existsSync(navDataDir)) { + fs.mkdirSync(navDataDir, { recursive: true }); + } + const section = builtNavTree['test-management']; + const keys = Object.keys(section).filter( + (k) => !NAV_META_KEYS.has(k) + ); + keys.forEach((key) => { + const filePath = path.join(navDataDir, `${key}.json`); + fs.writeFileSync(filePath, JSON.stringify(section[key])); + }); + console.log(`Wrote ${keys.length} nav-data JSON files for lazy loading.`); + } }; /* Create Header and Footer @@ -129,29 +179,29 @@ exports.sourceNodes = async ({ const { createNode } = actions; const getDirectories = (src) => glob.sync(`${src}/**/*`); - const paths = getDirectories('./src/pages/docs') + const pathsWithMeta = getDirectories('./src/pages/docs') .filter((val) => val.slice(-3) === '.md') .map((val) => { const { data } = frontmatter(fs.readFileSync(val)); const order = data.order || 200; - return [val, order]; + const title = data.title || ''; + return [val, order, title]; }) .sort((a, b) => Number(a[1]) - Number(b[1])) .map((val) => { - let newVal = ''; - newVal = val[0].replace(/\.\/src\/pages/g, ''); + let newVal = val[0].replace(/\.\/src\/pages/g, ''); newVal = newVal.substring(0, newVal.length - 3); newVal = newVal.slice(-5) === 'index' ? newVal.substring(0, newVal.length - 5) : newVal; - return `${newVal}/`; + return [`${newVal}/`, val[2]]; }) - .filter((val) => !ignorePaths.includes(val)); + .filter((val) => !ignorePaths.includes(val[0])); const output = {}; - paths.forEach((val) => { + pathsWithMeta.forEach(([val, pageTitle]) => { let split = val.split('/'); split = split.filter((url) => url !== ''); @@ -163,7 +213,6 @@ exports.sourceNodes = async ({ if (leftNavTitle[part]) { Object.keys(leftNavTitle[part]).forEach((key) => { if (val.indexOf(key) === 0) { - //console.log(key); current[part] = { leftNavTitle: leftNavTitle[part][key] }; } }); @@ -172,8 +221,12 @@ exports.sourceNodes = async ({ current = current[part]; }); current.url = `/${split.join('/')}/`; + if (pageTitle) { + current.title = pageTitle; + } }); - //console.log(output.docs) + + builtNavTree = output.docs; createNode(prepareNode(output.docs, 'leftNavLinks')); }; diff --git a/src/components/LeftNav.jsx b/src/components/LeftNav.jsx index 111cc9d..84dbf9b 100644 --- a/src/components/LeftNav.jsx +++ b/src/components/LeftNav.jsx @@ -1,15 +1,12 @@ /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions */ -import { useStaticQuery, graphql, Link } from 'gatsby'; -import React from 'react'; +import { Link } from 'gatsby'; +import React, { useState, useEffect, useCallback } from 'react'; import './LeftNav.scss'; -// import book from './images/book.png'; const { v4: uuidv4 } = require('uuid'); -let slugs; - const normalizePath = (path) => { if (!path) return '/'; return path.endsWith('/') ? path : `${path}/`; @@ -57,7 +54,7 @@ class ListItem extends React.Component { } const keys = Object.keys(itemData).filter( - (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' + (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' && key !== 'title' ); for (const key of keys) { @@ -98,7 +95,7 @@ class ListItem extends React.Component { } const keys = Object.keys(parsedData).filter( - (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' + (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' && key !== 'title' ); const panelsToExpand = []; @@ -176,10 +173,7 @@ class ListItem extends React.Component { }; child = (data, url) => { - const nameEntry = slugs.find( - (val) => normalizePath(url) === normalizePath(val.fields.slug) - ); - const title = nameEntry ? nameEntry.frontmatter.title : 'Unnamed Page'; + const title = data.leftNavTitle || data.title || 'Unnamed Page'; const { currentUrl } = this.state; if (!url) return null; @@ -188,14 +182,14 @@ class ListItem extends React.Component {
  • book - {data.leftNavTitle || title}{' '} + {title}{' '}
  • ); }; @@ -288,7 +282,7 @@ class ListItem extends React.Component { } const keys = Object.keys(parsedData).filter( - (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' + (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' && key !== 'title' ); return ( @@ -312,92 +306,175 @@ class ListItem extends React.Component { } } -const LeftNav = () => { - const data = useStaticQuery(graphql` - query { - allMarkdownRemark(sort: { fields: id, order: ASC }) { - nodes { - fields { - slug - } - frontmatter { - title - } - id - } - } - leftNavLinks { - value - } +const CaretSvg = ({ isExpanded }) => ( + + + +); + +const LeftNav = ({ navSubsections, activeSubSection, activeNavData }) => { + const [loadedSections, setLoadedSections] = useState({}); + const [expandedSections, setExpandedSections] = useState([]); + const [loadingSections, setLoadingSections] = useState({}); + + const currentPath = + typeof window !== 'undefined' + ? normalizePath(window.location.pathname) + : ''; + + useEffect(() => { + if (activeSubSection && !expandedSections.includes(activeSubSection)) { + setExpandedSections((prev) => + prev.includes(activeSubSection) ? prev : [...prev, activeSubSection] + ); } - `); - slugs = data.allMarkdownRemark.nodes; + }, [activeSubSection]); - let navDataToShow = null; - let rootIdentifier = 'docs'; - let rootParentPath = '/docs/'; + const loadSection = useCallback(async (key) => { + if (loadingSections[key]) return; + setLoadingSections((prev) => ({ ...prev, [key]: true })); + try { + const resp = await fetch(`/nav-data/${key}.json`); + if (!resp.ok) throw new Error(`HTTP ${resp.status}`); + const data = await resp.json(); + setLoadedSections((prev) => ({ ...prev, [key]: JSON.stringify(data) })); + } catch (err) { + console.error(`Failed to load nav data for "${key}":`, err); + } finally { + setLoadingSections((prev) => ({ ...prev, [key]: false })); + } + }, [loadingSections]); - let currentPath = ''; - if (typeof window !== 'undefined') { - currentPath = normalizePath(window.location.pathname); - } + const toggleSection = useCallback( + async (key) => { + if (expandedSections.includes(key)) { + setExpandedSections((prev) => prev.filter((k) => k !== key)); + return; + } - try { - const allNavData = JSON.parse(data.leftNavLinks.value); - const pathSegments = currentPath.split('/').filter(Boolean); + if (key !== activeSubSection && !loadedSections[key]) { + await loadSection(key); + } - let sectionKey = null; + setExpandedSections((prev) => [...prev, key]); + }, + [expandedSections, activeSubSection, loadedSections, loadSection] + ); - if (pathSegments.length >= 2 && allNavData[pathSegments[1]]) { - sectionKey = pathSegments[1]; // e.g., 'test-management' - } else if (pathSegments.length >= 1 && allNavData[pathSegments[0]]) { - sectionKey = pathSegments[0]; - } - // else { - // sectionKey = 'test-management'; - // } - - if (sectionKey && allNavData[sectionKey]) { - navDataToShow = allNavData[sectionKey]; - rootIdentifier = sectionKey; - rootParentPath = normalizePath(`/docs/${sectionKey}/`); - if (sectionKey === 'docs') { - rootParentPath = '/docs/'; - } - } else { - const defaultSection = 'test-management'; - if (allNavData[defaultSection]) { - navDataToShow = allNavData[defaultSection]; - rootIdentifier = defaultSection; - rootParentPath = normalizePath(`/docs/${defaultSection}/`); - } else { - console.warn( - `LeftNav: Could not determine section from URL "${currentPath}" and default "${defaultSection}" not found.` - ); - navDataToShow = null; - } - } - } catch (e) { - console.error('LeftNav: Failed to parse leftNavLinks.value', e); - navDataToShow = null; - } + const getSectionData = useCallback( + (key) => { + if (key === activeSubSection && activeNavData) return activeNavData; + return loadedSections[key] || null; + }, + [activeSubSection, activeNavData, loadedSections] + ); - return ( - <> + if (!navSubsections || navSubsections.length === 0) { + return (
    - {navDataToShow ? ( - - ) : ( -

    Navigation section not available.

    - )} +

    Navigation not available.

    - + ); + } + + return ( +
    + {navSubsections.map((section) => { + const isExpanded = expandedSections.includes(section.key); + const sectionData = getSectionData(section.key); + const basePath = normalizePath( + `/docs/test-management/${section.key}/` + ); + const isActive = currentPath.startsWith(basePath); + + if (section.isLeaf) { + return ( +
  • +
    + book + + {section.title} + +
  • + ); + } + + return ( + + ); + })} +
    ); }; diff --git a/src/components/MobileView.jsx b/src/components/MobileView.jsx index 5420ffa..6b7761d 100644 --- a/src/components/MobileView.jsx +++ b/src/components/MobileView.jsx @@ -1,4 +1,4 @@ -import React , {Component} from "react"; +import React from "react"; import LeftNav from "../components/LeftNav"; import "./MobileView.scss" @@ -8,16 +8,21 @@ class MobileView extends React.Component{ divcontainer:false, } render() { - const handleChange = (e) => { + const handleChange = () => { this.setState({divcontainer:!this.state.divcontainer}); } + const { navSubsections, activeSubSection, activeNavData } = this.props; const x = this.state.divcontainer; return ( <>
    - + ) diff --git a/src/pages/docs/test-management/index.jsx b/src/pages/docs/test-management/index.jsx index 613c4f8..220f268 100644 --- a/src/pages/docs/test-management/index.jsx +++ b/src/pages/docs/test-management/index.jsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-danger */ -import React, { useEffect } from 'react'; +import React, { useMemo } from 'react'; import { graphql, Link } from 'gatsby'; import Layout from '../../../components/layout'; import SEO from '../../../components/seo'; @@ -11,6 +11,23 @@ import '../../../templates/page.scss'; import CardList from '../../../components/navcards'; import Header from '../../../components/header'; +const META_KEYS = new Set(['leftNavTitle', 'old', 'overview', 'url', 'title']); + +function buildSubsectionMeta(sectionData) { + const keys = Object.keys(sectionData).filter((k) => !META_KEYS.has(k)); + return keys.map((key) => { + const item = sectionData[key]; + const childKeys = Object.keys(item).filter((k) => !META_KEYS.has(k)); + const isLeaf = !!item.url && childKeys.length === 0; + return { + key, + title: item.leftNavTitle || key.replaceAll('-', ' '), + overviewUrl: item?.overview?.url || (isLeaf ? item.url : null), + isLeaf, + }; + }); +} + const IndexContent = () => { return ( <> @@ -31,8 +48,8 @@ const IndexContent = () => {
    -
    -
    +
    +
    @@ -76,7 +93,19 @@ const IndexContent = () => { ); }; -const Index = () => { +const Index = ({ data }) => { + const navProps = useMemo(() => { + if (!data?.leftNavLinks?.value) return {}; + try { + const allNavData = JSON.parse(data.leftNavLinks.value); + const section = allNavData['test-management']; + if (!section) return {}; + return { navSubsections: buildSubsectionMeta(section) }; + } catch { + return {}; + } + }, [data]); + return ( {
    - +
    @@ -109,3 +138,12 @@ const Index = () => { }; export default Index; + +export const pageQuery = graphql` + query { + leftNavLinks { + value + } + } +`; +/* eslint-enable */ diff --git a/src/templates/page.jsx b/src/templates/page.jsx index dd0dd90..04d80c7 100644 --- a/src/templates/page.jsx +++ b/src/templates/page.jsx @@ -30,6 +30,12 @@ export default ({ data, pageContext }) => { } : null; + const navProps = { + navSubsections: pageContext.navSubsections, + activeSubSection: pageContext.activeSubSection, + activeNavData: pageContext.activeNavData, + }; + const post = data.markdownRemark; if (environment.isStaging()) { post.frontmatter.noindex = true; @@ -127,9 +133,9 @@ export default ({ data, pageContext }) => { {/**/}
    - +
    diff --git a/tailwind.config.js b/tailwind.config.js index 403c08c..647608e 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,6 +1,6 @@ module.exports = { - purge: [], - darkMode: false, // or 'media' or 'class' + purge: ['./src/**/*.{js,jsx,ts,tsx}'], + darkMode: false, theme: { extend: { colors: { From 7a63773c7de0e5637b319be78c64b8625e0980f3 Mon Sep 17 00:00:00 2001 From: Bharath Krishna <118433150+bharathk08@users.noreply.github.com> Date: Thu, 26 Mar 2026 15:43:08 +0530 Subject: [PATCH 2/3] Merge pull request #124 from testsigmahq/Fix/book-load Update leftnav.jsx --- src/components/LeftNav.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/LeftNav.jsx b/src/components/LeftNav.jsx index 84dbf9b..34948d0 100644 --- a/src/components/LeftNav.jsx +++ b/src/components/LeftNav.jsx @@ -188,7 +188,7 @@ class ListItem extends React.Component { }`} >
    - book + book {title}{' '} ); From bb7f5ba037e68bc975fa8b4368f2041e603609ae Mon Sep 17 00:00:00 2001 From: Abdul-jailani Date: Thu, 26 Mar 2026 15:59:40 +0530 Subject: [PATCH 3/3] Fixed left nav issue --- gatsby-node.js | 71 +----- src/components/LeftNav.jsx | 261 ++++++++--------------- src/components/MobileView.jsx | 11 +- src/pages/docs/test-management/index.jsx | 50 +---- src/templates/page.jsx | 10 +- 5 files changed, 112 insertions(+), 291 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 61bb35b..9e834dd 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -9,26 +9,6 @@ const leftNavTitle = require('./src/left-nav-title.json'); const ignorePaths = []; -let builtNavTree = null; - -const NAV_META_KEYS = new Set(['leftNavTitle', 'old', 'overview', 'url', 'title']); - -function extractSubsectionMeta(sectionData) { - const keys = Object.keys(sectionData).filter( - (k) => !NAV_META_KEYS.has(k) - ); - return keys.map((key) => { - const item = sectionData[key]; - const isLeaf = !!item.url && Object.keys(item).filter((k) => !NAV_META_KEYS.has(k)).length === 0; - return { - key, - title: item.leftNavTitle || key.replaceAll('-', ' '), - overviewUrl: item?.overview?.url || (isLeaf ? item.url : null), - isLeaf, - }; - }); -} - exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions; if (node.internal.type === 'MarkdownRemark') { @@ -76,9 +56,6 @@ exports.createPages = async ({ graphql, actions }) => { } } `); - const mainSection = builtNavTree?.['test-management'] ?? null; - const navSubsections = mainSection ? extractSubsectionMeta(mainSection) : []; - result.data.allMarkdownRemark.edges.forEach(({ node }, index) => { if (node.fields.slug.includes('-')) { const underscoreSlug = node.fields.slug.replace(/-/g, '_'); @@ -90,14 +67,6 @@ exports.createPages = async ({ graphql, actions }) => { toPath: node.fields.slug, }); } - - const slugParts = node.fields.slug.split('/').filter(Boolean); - const activeSubSection = slugParts.length >= 3 ? slugParts[2] : null; - const activeNavData = - activeSubSection && mainSection && mainSection[activeSubSection] - ? JSON.stringify(mainSection[activeSubSection]) - : null; - createPage({ path: node.fields.slug, component: path.resolve('./src/templates/page.jsx'), @@ -111,9 +80,6 @@ exports.createPages = async ({ graphql, actions }) => { index === result.data.allMarkdownRemark.edges.length - 1 ? null : result.data.allMarkdownRemark.edges[index + 1].node, - navSubsections, - activeSubSection, - activeNavData, }, }); }); @@ -129,22 +95,6 @@ exports.onPostBuild = () => { } else { console.error('Sitemap.xml not found in src/pages/docs/'); } - - if (builtNavTree?.['test-management']) { - const navDataDir = path.join(__dirname, 'public', 'nav-data'); - if (!fs.existsSync(navDataDir)) { - fs.mkdirSync(navDataDir, { recursive: true }); - } - const section = builtNavTree['test-management']; - const keys = Object.keys(section).filter( - (k) => !NAV_META_KEYS.has(k) - ); - keys.forEach((key) => { - const filePath = path.join(navDataDir, `${key}.json`); - fs.writeFileSync(filePath, JSON.stringify(section[key])); - }); - console.log(`Wrote ${keys.length} nav-data JSON files for lazy loading.`); - } }; /* Create Header and Footer @@ -179,29 +129,29 @@ exports.sourceNodes = async ({ const { createNode } = actions; const getDirectories = (src) => glob.sync(`${src}/**/*`); - const pathsWithMeta = getDirectories('./src/pages/docs') + const paths = getDirectories('./src/pages/docs') .filter((val) => val.slice(-3) === '.md') .map((val) => { const { data } = frontmatter(fs.readFileSync(val)); const order = data.order || 200; - const title = data.title || ''; - return [val, order, title]; + return [val, order]; }) .sort((a, b) => Number(a[1]) - Number(b[1])) .map((val) => { - let newVal = val[0].replace(/\.\/src\/pages/g, ''); + let newVal = ''; + newVal = val[0].replace(/\.\/src\/pages/g, ''); newVal = newVal.substring(0, newVal.length - 3); newVal = newVal.slice(-5) === 'index' ? newVal.substring(0, newVal.length - 5) : newVal; - return [`${newVal}/`, val[2]]; + return `${newVal}/`; }) - .filter((val) => !ignorePaths.includes(val[0])); + .filter((val) => !ignorePaths.includes(val)); const output = {}; - pathsWithMeta.forEach(([val, pageTitle]) => { + paths.forEach((val) => { let split = val.split('/'); split = split.filter((url) => url !== ''); @@ -213,6 +163,7 @@ exports.sourceNodes = async ({ if (leftNavTitle[part]) { Object.keys(leftNavTitle[part]).forEach((key) => { if (val.indexOf(key) === 0) { + //console.log(key); current[part] = { leftNavTitle: leftNavTitle[part][key] }; } }); @@ -221,12 +172,8 @@ exports.sourceNodes = async ({ current = current[part]; }); current.url = `/${split.join('/')}/`; - if (pageTitle) { - current.title = pageTitle; - } }); - - builtNavTree = output.docs; + //console.log(output.docs) createNode(prepareNode(output.docs, 'leftNavLinks')); }; diff --git a/src/components/LeftNav.jsx b/src/components/LeftNav.jsx index 34948d0..111cc9d 100644 --- a/src/components/LeftNav.jsx +++ b/src/components/LeftNav.jsx @@ -1,12 +1,15 @@ /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions */ -import { Link } from 'gatsby'; -import React, { useState, useEffect, useCallback } from 'react'; +import { useStaticQuery, graphql, Link } from 'gatsby'; +import React from 'react'; import './LeftNav.scss'; +// import book from './images/book.png'; const { v4: uuidv4 } = require('uuid'); +let slugs; + const normalizePath = (path) => { if (!path) return '/'; return path.endsWith('/') ? path : `${path}/`; @@ -54,7 +57,7 @@ class ListItem extends React.Component { } const keys = Object.keys(itemData).filter( - (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' && key !== 'title' + (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' ); for (const key of keys) { @@ -95,7 +98,7 @@ class ListItem extends React.Component { } const keys = Object.keys(parsedData).filter( - (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' && key !== 'title' + (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' ); const panelsToExpand = []; @@ -173,7 +176,10 @@ class ListItem extends React.Component { }; child = (data, url) => { - const title = data.leftNavTitle || data.title || 'Unnamed Page'; + const nameEntry = slugs.find( + (val) => normalizePath(url) === normalizePath(val.fields.slug) + ); + const title = nameEntry ? nameEntry.frontmatter.title : 'Unnamed Page'; const { currentUrl } = this.state; if (!url) return null; @@ -182,14 +188,14 @@ class ListItem extends React.Component {
  • - book - {title}{' '} + book + {data.leftNavTitle || title}{' '}
  • ); }; @@ -282,7 +288,7 @@ class ListItem extends React.Component { } const keys = Object.keys(parsedData).filter( - (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' && key !== 'title' + (key) => key !== 'leftNavTitle' && key !== 'old' && key !== 'overview' ); return ( @@ -306,175 +312,92 @@ class ListItem extends React.Component { } } -const CaretSvg = ({ isExpanded }) => ( - - - -); - -const LeftNav = ({ navSubsections, activeSubSection, activeNavData }) => { - const [loadedSections, setLoadedSections] = useState({}); - const [expandedSections, setExpandedSections] = useState([]); - const [loadingSections, setLoadingSections] = useState({}); - - const currentPath = - typeof window !== 'undefined' - ? normalizePath(window.location.pathname) - : ''; - - useEffect(() => { - if (activeSubSection && !expandedSections.includes(activeSubSection)) { - setExpandedSections((prev) => - prev.includes(activeSubSection) ? prev : [...prev, activeSubSection] - ); - } - }, [activeSubSection]); - - const loadSection = useCallback(async (key) => { - if (loadingSections[key]) return; - setLoadingSections((prev) => ({ ...prev, [key]: true })); - try { - const resp = await fetch(`/nav-data/${key}.json`); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const data = await resp.json(); - setLoadedSections((prev) => ({ ...prev, [key]: JSON.stringify(data) })); - } catch (err) { - console.error(`Failed to load nav data for "${key}":`, err); - } finally { - setLoadingSections((prev) => ({ ...prev, [key]: false })); - } - }, [loadingSections]); - - const toggleSection = useCallback( - async (key) => { - if (expandedSections.includes(key)) { - setExpandedSections((prev) => prev.filter((k) => k !== key)); - return; +const LeftNav = () => { + const data = useStaticQuery(graphql` + query { + allMarkdownRemark(sort: { fields: id, order: ASC }) { + nodes { + fields { + slug + } + frontmatter { + title + } + id + } } - - if (key !== activeSubSection && !loadedSections[key]) { - await loadSection(key); + leftNavLinks { + value } + } + `); + slugs = data.allMarkdownRemark.nodes; - setExpandedSections((prev) => [...prev, key]); - }, - [expandedSections, activeSubSection, loadedSections, loadSection] - ); - - const getSectionData = useCallback( - (key) => { - if (key === activeSubSection && activeNavData) return activeNavData; - return loadedSections[key] || null; - }, - [activeSubSection, activeNavData, loadedSections] - ); + let navDataToShow = null; + let rootIdentifier = 'docs'; + let rootParentPath = '/docs/'; - if (!navSubsections || navSubsections.length === 0) { - return ( -
    -

    Navigation not available.

    -
    - ); + let currentPath = ''; + if (typeof window !== 'undefined') { + currentPath = normalizePath(window.location.pathname); } - return ( -
    - {navSubsections.map((section) => { - const isExpanded = expandedSections.includes(section.key); - const sectionData = getSectionData(section.key); - const basePath = normalizePath( - `/docs/test-management/${section.key}/` - ); - const isActive = currentPath.startsWith(basePath); - - if (section.isLeaf) { - return ( -
  • -
    - book - - {section.title} - -
  • - ); - } + try { + const allNavData = JSON.parse(data.leftNavLinks.value); + const pathSegments = currentPath.split('/').filter(Boolean); - return ( -
      -
    • -
      toggleSection(section.key)} - identifier={section.key} - > - - {section.overviewUrl ? ( - e.stopPropagation()} - className={ - currentPath === normalizePath(section.overviewUrl) - ? 'font-semibold' - : '' - } - > - {section.title} - - ) : ( - {section.title} - )} -
      -
    • - - {isExpanded && sectionData && ( - - )} + let sectionKey = null; - {isExpanded && !sectionData && loadingSections[section.key] && ( -
    • - Loading… -
    • - )} -
    + if (pathSegments.length >= 2 && allNavData[pathSegments[1]]) { + sectionKey = pathSegments[1]; // e.g., 'test-management' + } else if (pathSegments.length >= 1 && allNavData[pathSegments[0]]) { + sectionKey = pathSegments[0]; + } + // else { + // sectionKey = 'test-management'; + // } + + if (sectionKey && allNavData[sectionKey]) { + navDataToShow = allNavData[sectionKey]; + rootIdentifier = sectionKey; + rootParentPath = normalizePath(`/docs/${sectionKey}/`); + if (sectionKey === 'docs') { + rootParentPath = '/docs/'; + } + } else { + const defaultSection = 'test-management'; + if (allNavData[defaultSection]) { + navDataToShow = allNavData[defaultSection]; + rootIdentifier = defaultSection; + rootParentPath = normalizePath(`/docs/${defaultSection}/`); + } else { + console.warn( + `LeftNav: Could not determine section from URL "${currentPath}" and default "${defaultSection}" not found.` ); - })} -
    + navDataToShow = null; + } + } + } catch (e) { + console.error('LeftNav: Failed to parse leftNavLinks.value', e); + navDataToShow = null; + } + + return ( + <> +
    + {navDataToShow ? ( + + ) : ( +

    Navigation section not available.

    + )} +
    + ); }; diff --git a/src/components/MobileView.jsx b/src/components/MobileView.jsx index 6b7761d..5420ffa 100644 --- a/src/components/MobileView.jsx +++ b/src/components/MobileView.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React , {Component} from "react"; import LeftNav from "../components/LeftNav"; import "./MobileView.scss" @@ -8,21 +8,16 @@ class MobileView extends React.Component{ divcontainer:false, } render() { - const handleChange = () => { + const handleChange = (e) => { this.setState({divcontainer:!this.state.divcontainer}); } - const { navSubsections, activeSubSection, activeNavData } = this.props; const x = this.state.divcontainer; return ( <>
    - + ) diff --git a/src/pages/docs/test-management/index.jsx b/src/pages/docs/test-management/index.jsx index 220f268..613c4f8 100644 --- a/src/pages/docs/test-management/index.jsx +++ b/src/pages/docs/test-management/index.jsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-danger */ -import React, { useMemo } from 'react'; +import React, { useEffect } from 'react'; import { graphql, Link } from 'gatsby'; import Layout from '../../../components/layout'; import SEO from '../../../components/seo'; @@ -11,23 +11,6 @@ import '../../../templates/page.scss'; import CardList from '../../../components/navcards'; import Header from '../../../components/header'; -const META_KEYS = new Set(['leftNavTitle', 'old', 'overview', 'url', 'title']); - -function buildSubsectionMeta(sectionData) { - const keys = Object.keys(sectionData).filter((k) => !META_KEYS.has(k)); - return keys.map((key) => { - const item = sectionData[key]; - const childKeys = Object.keys(item).filter((k) => !META_KEYS.has(k)); - const isLeaf = !!item.url && childKeys.length === 0; - return { - key, - title: item.leftNavTitle || key.replaceAll('-', ' '), - overviewUrl: item?.overview?.url || (isLeaf ? item.url : null), - isLeaf, - }; - }); -} - const IndexContent = () => { return ( <> @@ -48,8 +31,8 @@ const IndexContent = () => {
    -
    -
    +
    +
    @@ -93,19 +76,7 @@ const IndexContent = () => { ); }; -const Index = ({ data }) => { - const navProps = useMemo(() => { - if (!data?.leftNavLinks?.value) return {}; - try { - const allNavData = JSON.parse(data.leftNavLinks.value); - const section = allNavData['test-management']; - if (!section) return {}; - return { navSubsections: buildSubsectionMeta(section) }; - } catch { - return {}; - } - }, [data]); - +const Index = () => { return ( {
    - +
    @@ -138,12 +109,3 @@ const Index = ({ data }) => { }; export default Index; - -export const pageQuery = graphql` - query { - leftNavLinks { - value - } - } -`; -/* eslint-enable */ diff --git a/src/templates/page.jsx b/src/templates/page.jsx index 04d80c7..dd0dd90 100644 --- a/src/templates/page.jsx +++ b/src/templates/page.jsx @@ -30,12 +30,6 @@ export default ({ data, pageContext }) => { } : null; - const navProps = { - navSubsections: pageContext.navSubsections, - activeSubSection: pageContext.activeSubSection, - activeNavData: pageContext.activeNavData, - }; - const post = data.markdownRemark; if (environment.isStaging()) { post.frontmatter.noindex = true; @@ -133,9 +127,9 @@ export default ({ data, pageContext }) => { {/**/}
    - +