Root.js
1 // SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai> 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 import React, {useEffect, useState} from 'react'; 6 import Root from '@theme-original/Root'; 7 import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 8 9 export default function RootWrapper(props) { 10 const {siteConfig} = useDocusaurusContext(); 11 12 // Determine product from URL path or environment 13 const getProduct = () => { 14 if (typeof window !== 'undefined') { 15 const path = window.location.pathname; 16 if (path.startsWith('/professional')) return 'professional'; 17 if (path.startsWith('/enterprise')) return 'enterprise'; 18 } 19 return siteConfig?.customFields?.docsProduct || 20 (typeof process !== 'undefined' && process.env.DOCS_PRODUCT) || 21 'haystack'; 22 }; 23 24 const [product, setProduct] = useState(getProduct); 25 26 // Update product when location changes 27 useEffect(() => { 28 const handleLocationChange = () => { 29 const newProduct = getProduct(); 30 console.log('[Root.js] Location changed, setting product to:', newProduct); 31 setProduct(newProduct); 32 }; 33 34 // Listen for route changes 35 if (typeof window !== 'undefined') { 36 window.addEventListener('popstate', handleLocationChange); 37 // Also check on initial load and navigation 38 handleLocationChange(); 39 } 40 41 return () => { 42 if (typeof window !== 'undefined') { 43 window.removeEventListener('popstate', handleLocationChange); 44 } 45 }; 46 }, []); 47 48 // Mark single-word sidebar items for truncation styling 49 useEffect(() => { 50 if (typeof document === 'undefined') { 51 return; 52 } 53 54 const markSingleWordLinks = () => { 55 const menuLinks = document.querySelectorAll('.menu__link'); 56 menuLinks.forEach(link => { 57 // Get the text content, trimmed 58 const text = link.textContent?.trim() || ''; 59 // Check if it's a single word (no spaces) 60 const isSingleWord = text.length > 0 && !text.includes(' '); 61 62 if (isSingleWord) { 63 link.classList.add('menu__link--single-word'); 64 } else { 65 link.classList.remove('menu__link--single-word'); 66 } 67 }); 68 }; 69 70 // Run initially 71 markSingleWordLinks(); 72 73 // Re-run when DOM changes (sidebar updates, navigation, etc.) 74 const observer = new MutationObserver(markSingleWordLinks); 75 observer.observe(document.body, {childList: true, subtree: true}); 76 77 return () => { 78 observer.disconnect(); 79 }; 80 }, []); 81 82 useEffect(() => { 83 console.log('[Root.js] Current product:', product); 84 console.log('[Root.js] Current path:', typeof window !== 'undefined' ? window.location.pathname : 'N/A'); 85 if (typeof document === 'undefined') { 86 return; 87 } 88 89 document.documentElement.setAttribute('data-docs-product', product); 90 91 const filterToc = () => { 92 console.log('[Root.js] filterToc called, product:', product); 93 const items = document.querySelectorAll('.table-of-contents__item'); 94 console.log('[Root.js] Found TOC items:', items.length); 95 96 items.forEach(item => { 97 const link = item.querySelector('.table-of-contents__link'); 98 if (!link) { 99 return; 100 } 101 const href = link.getAttribute('href') || ''; 102 const isEnterprise = href.startsWith('#enterprise-'); 103 const isProfessional = href.startsWith('#professional-'); 104 105 console.log('[Root.js] TOC item:', {href, isEnterprise, isProfessional, product}); 106 107 if ( 108 (product === 'professional' && isEnterprise) || 109 (product === 'enterprise' && isProfessional) 110 ) { 111 console.log('[Root.js] Removing TOC item:', href); 112 item.parentElement?.removeChild(item); 113 } 114 }); 115 }; 116 117 filterToc(); 118 119 const observer = new MutationObserver(filterToc); 120 observer.observe(document.body, {childList: true, subtree: true}); 121 122 return () => { 123 document.documentElement.removeAttribute('data-docs-product'); 124 observer.disconnect(); 125 }; 126 }, [product]); 127 128 return <Root {...props} />; 129 }